library(coda)
library(bayesplot) 
library(ggplot2)
library(ggsci)
library(khroma)
library(tidyverse)
library(reshape2)
library(yardstick)
library(here)
knitr::opts_chunk$set(echo = TRUE, dpi = 300 )

Set up MCSim file

# this markdown file must be saved in top level directory for the following to work; the mcsim code depends on getwd results.
mdir <- "MCSim"
source(here::here(mdir,"setup_MCSim.R"))
# Make mod.exe (used to create mcsim executable from model file)
makemod() 
The mod.exe had been created.

Set filenames and load data

Set up dataset

id_lut <- multicheck$df_check %>% select(Level) %>% unique ()  %>%
  mutate(dataset = c( 
    rep("Decatur M Train", 9),
    rep("Decatur F Train", 9),
    rep("Decatur M Test", 9),
    rep("Decatur F Test", 10),
    'Paulsboro-Train','Horsham-Train',
    'Warminster-Test'), 
    Sex = c( 
    rep("M", 9),
    rep("F", 9),
    rep("M", 9),
    rep("F", 10),
    'Mixed', 'Mixed',  'Mixed'),
    City = c( 
    rep("Decatur", 18),
    rep("Decatur", 19),
    'Paulsboro','Horsham','Warminster'), 
    Train_Test = c( 
    rep("Train", 9),
    rep("Train", 9),
    rep("Test", 9),
    rep("Test", 10),
    'Train',  'Train', 'Test'),
    datatype = c(
      rep("Individual",9+9+9+10),
      rep("Summary",3)),
    Simulation = row_number(),
    variable = paste0(dataset, " ",Simulation))

id_lut$dataset <- factor(id_lut$dataset,levels=
                           c("Decatur M Train","Decatur F Train","Arnsberg M Train",
                             "Arnsberg F Train","Decatur M Test","Decatur F Test","Arnsberg M Test",
                             "Arnsberg F Test","Minnesota Train","Minnesota Test",
                             'Lubeck-Bartell-Train', 'Lubeck-Bartell-Test',
                             'Little Hocking-Bartell-Train', 'Little Hocking-Bartell-Test',
                             'Little Hocking-Emmett-Test','Paulsboro-Train','Horsham-Train',
                             'Warminster-Test','Warrington-Train'))
id_lut$City <- factor(id_lut$City,levels = 
                        c("Decatur","Arnsberg","Minnesota",'Lubeck-Bartell',
                          'Little Hocking-Bartell','Little Hocking-Emmett',
                          'Paulsboro','Horsham','Warminster','Warrington'))
 
indiv_lut <- id_lut %>% 
  filter(City %in% c("Decatur")) %>%
  mutate(  dataset = as.factor(dataset))

nv <- data.frame(dataset =unique(indiv_lut$dataset), 
           variable= rep("Pop GM", 4),
           type= rep("Pop GM", 4), stringsAsFactors = FALSE)

Individual parameters

set.seed(314159)

indiv_parms <- indiv_lut
lnkparmnames <- paste("ln_k.",gsub("_",".",indiv_parms$Level),".",sep="")
lnVdparmnames <- paste("ln_Vd.",gsub("_",".",indiv_parms$Level),".",sep="")

parmsamp <- apply(multicheck$parms.samp,2,sample,1)

## Random z-score estimate of each parameter
indiv_parms$ln_k.z.samp <- parmsamp[lnkparmnames]
indiv_parms$ln_Vd.z.samp <- parmsamp[lnVdparmnames]

normd <- data.frame(x=qnorm(ppoints(200)))
normd$y <- dnorm(normd$x)

iplotk<-
  ggplot(subset(indiv_parms,Train_Test=="Train"))+
    geom_histogram(aes(x=ln_k.z.samp,after_stat(density)),bins=10)+facet_wrap(~City,ncol=1)+
    geom_line(aes(x=x,y=y),data=normd)+
    xlab("Individual z-scores for k") + theme_bw()

iplotVd<-
  ggplot(subset(indiv_parms,Train_Test=="Train"))+
    geom_histogram(aes(x=ln_Vd.z.samp,after_stat(density)),bins=10)+facet_wrap(~City,ncol=1)+
    geom_line(aes(x=x,y=y),data=normd)+
    xlab("Individual z-scores for Vd") + theme_bw()

print(iplotk)

print(iplotVd)

ggsave(file.path("output-plots",
             paste0( sa,"Indiv_zscores_k_PFNA.pdf")),iplotk,dpi=600)
Saving 3.5 x 3.5 in image
ggsave(file.path("output-plots",
             paste0( sa,"Indiv_zscores_Vd_PFNA.pdf")),iplotVd,dpi=600)
Saving 3.5 x 3.5 in image
ggsave(file.path("output-plots",
             paste0( sa,"Indiv_zscores_k_PFNA.png")),iplotk,dpi=600)
Saving 3.5 x 3.5 in image
ggsave(file.path("output-plots",
             paste0( sa,"Indiv_zscores_Vd_PFNA.png")),iplotVd,dpi=600)
Saving 3.5 x 3.5 in image

Scatter plot of predictions (median of multicheck samples) versus data.

This is a Figure 2 panel. Needed to use “scale=1.1” in ggsave to match PFOA.

nrow(multicheck$df_check)
[1] 38500
nrow(id_lut)
[1] 40
multicheck$df_check %>% left_join(id_lut) %>% nrow()
Joining, by = c("Level", "Simulation")
[1] 38500
names(multicheck$df_check)
[1] "Level"      "Simulation" "Output_Var" "Time"       "Data"      
[6] "Prediction"
Level

Simulation

Output_Var

Time

Data

Prediction
multicheck2 <- multicheck$df_check %>% left_join(id_lut)%>% 
  group_by_at ( vars(-Prediction)) %>% 
  summarise(Prediction = median(Prediction)) %>%
  ungroup() %>%
  group_by(City) %>% 
  mutate(Train_Test = factor(Train_Test, levels = c("Train", "Test")),
         `City (datatype)` = factor (paste0("\n" , City, "\n(", datatype, ")\n") ),
         label = case_when(Train_Test=="Train" ~ "E: PFNA Train",
                           Train_Test=="Test"  ~ "F: PFNA Test",
                           TRUE ~ ""))
Joining, by = c("Level", "Simulation")
`summarise()` has grouped output by 'Level', 'Simulation', 'Output_Var', 'Time', 'Data', 'dataset', 'Sex', 'City', 'Train_Test', 'datatype'. You can override using the `.groups` argument.
 #define color for testing boxplots
bp_cols <- c (as.character (khroma::colour("muted")(9)) , "#191919")   
bp_cols <-bp_cols[c(1, 7, 9:8)]# plot_scheme_colourblind(bp_cols) 

### Create aesthetics lookup
aes_lut <- multicheck2 %>% ungroup() %>% 
  group_by(City, datatype,  `City (datatype)` ) %>% summarise () %>% ungroup() %>%
  mutate( cols = bp_cols, city_fills =   bp_cols , 
          # for individual level on point plot (multicheck2), darken outlines for visibility, use standard colors otherwise
         city_outlines =  if_else(datatype == "Individual"  ,  colorspace::darken(city_fills, 0.3), city_fills) ,  
         shapes = case_when(datatype == "Individual"  & `City` %in% c('Decatur', 'Arnsberg', 'Minnesota')   ~  23,
                            datatype == "Summary" &`City` %in% c("Horsham", "Warminster",  "Warrington") ~ 2,
                            datatype == "Summary" & `City` == "Paulsboro" ~ 1,
                            TRUE ~ 18                                ), 
         size = if_else(datatype =="Individual", 1.75, 2.5 ) )  
`summarise()` has grouped output by 'City', 'datatype'. You can override using the `.groups` argument.
source( paste0(gsub(basename(here()), 'shared_functions', here()), '/plot_scatter_mcheck.r'))

p2 <- plot_scatter_mcheck(dframe = multicheck2, pfas_nom = pfas_name, aes_lut_fn = aes_lut )
Joining, by = "facet_label"
print(p2) 

ggsave(here ("output-plots", paste0( sa,"multicheckplot_", pfas_name,
               ".pdf")),p2,dpi=600, scale=1.1)
Saving 8.8 x 3.85 in image
ggsave(here ("output-plots", paste0( sa,"multicheckplot_", pfas_name,
               ".png")),p2,dpi=600, scale=1.1) # doesn't properly handle '\n' unicode for line feed. Not sure why; possibly device opens from windows working environment. 
Saving 8.8 x 3.85 in image
multicheck2$PFAS <- "PFNA"
multiplot_scatter_dat <- list(aes_lut = aes_lut, multicheck2 = multicheck2) # save out for use in commbined plot
save(multiplot_scatter_dat, file= "pfna_multiplot_scatter.Rdata")

Parse multicheck

df_check <- multicheck$df_check
df_check <- subset(df_check,Data > 0) 

n1 <- nrow(df_check)
id_chks <- df_check %>% select(Level) %>% unique() %>% bind_cols(id_lut)  %>%
  mutate(dataset = as.factor(dataset), Sex = as.factor(Sex), City = as.factor(City), 
         Train_Test = as.factor(Train_Test))
New names:
* Level -> Level...1
* Level -> Level...2
df_check <- df_check %>% left_join(id_chks, by = "Simulation")%>%
  mutate(Dataset = paste(as.character(dataset), Simulation),
         Sex = ordered(Sex, levels = c("M", "F", "Mixed"), 
                       labels = c("Male", "Female", "Mixed (all sexes)")))
n2 <- nrow(df_check)
if(n1 != n2)print("duplicates created in id-lut join")
df_check$Time.desc <- as.character(paste0("T=",df_check$Time))
df_check$Time.desc[df_check$Time.desc == "T=1e-06"] <- "SteadyState"
df_check$Dataset.Time <- interaction(df_check$Dataset,
                                     df_check$Time.desc,lex.order=TRUE)
df_check$Dataset.Time <- factor(df_check$Dataset.Time,
                                levels=levels(df_check$Dataset.Time))
calibdata <- df_check[,names(df_check) != "Prediction"]
calibdata <- calibdata[!duplicated(calibdata),]
print(calibdata)
        Level Simulation Output_Var  Time  Data  Level...1  Level...2
1   1_1_1_1_1          1     Cserum 0.000 1.900  1_1_1_1_1  1_1_1_1_1
2   1_1_1_1_1          1     Cserum 5.802 1.100  1_1_1_1_1  1_1_1_1_1
3   1_1_1_1_2          2     Cserum 0.000 1.100  1_1_1_1_2  1_1_1_1_2
4   1_1_1_1_2          2     Cserum 5.802 0.900  1_1_1_1_2  1_1_1_1_2
5   1_1_1_1_3          3     Cserum 0.000 2.100  1_1_1_1_3  1_1_1_1_3
6   1_1_1_1_3          3     Cserum 5.802 0.700  1_1_1_1_3  1_1_1_1_3
7   1_1_1_1_4          4     Cserum 0.000 1.900  1_1_1_1_4  1_1_1_1_4
8   1_1_1_1_4          4     Cserum 5.802 0.500  1_1_1_1_4  1_1_1_1_4
9   1_1_1_1_5          5     Cserum 0.000 3.500  1_1_1_1_5  1_1_1_1_5
10  1_1_1_1_5          5     Cserum 5.802 0.900  1_1_1_1_5  1_1_1_1_5
11  1_1_1_1_6          6     Cserum 0.000 1.200  1_1_1_1_6  1_1_1_1_6
12  1_1_1_1_6          6     Cserum 5.802 0.600  1_1_1_1_6  1_1_1_1_6
13  1_1_1_1_7          7     Cserum 0.000 2.700  1_1_1_1_7  1_1_1_1_7
14  1_1_1_1_7          7     Cserum 5.802 0.800  1_1_1_1_7  1_1_1_1_7
15  1_1_1_1_8          8     Cserum 0.000 1.700  1_1_1_1_8  1_1_1_1_8
16  1_1_1_1_8          8     Cserum 5.802 0.500  1_1_1_1_8  1_1_1_1_8
17  1_1_1_1_9          9     Cserum 0.000 1.100  1_1_1_1_9  1_1_1_1_9
18  1_1_1_1_9          9     Cserum 5.802 0.600  1_1_1_1_9  1_1_1_1_9
19 1_1_1_1_10         10     Cserum 0.000 1.600 1_1_1_1_10 1_1_1_1_10
20 1_1_1_1_10         10     Cserum 5.802 1.000 1_1_1_1_10 1_1_1_1_10
21 1_1_1_1_11         11     Cserum 0.000 2.000 1_1_1_1_11 1_1_1_1_11
22 1_1_1_1_11         11     Cserum 5.802 1.100 1_1_1_1_11 1_1_1_1_11
23 1_1_1_1_12         12     Cserum 0.000 1.000 1_1_1_1_12 1_1_1_1_12
24 1_1_1_1_12         12     Cserum 5.802 0.400 1_1_1_1_12 1_1_1_1_12
25 1_1_1_1_13         13     Cserum 0.000 1.700 1_1_1_1_13 1_1_1_1_13
26 1_1_1_1_13         13     Cserum 5.802 0.400 1_1_1_1_13 1_1_1_1_13
27 1_1_1_1_14         14     Cserum 0.000 3.900 1_1_1_1_14 1_1_1_1_14
28 1_1_1_1_14         14     Cserum 5.802 1.200 1_1_1_1_14 1_1_1_1_14
29 1_1_1_1_15         15     Cserum 0.000 2.400 1_1_1_1_15 1_1_1_1_15
30 1_1_1_1_15         15     Cserum 5.802 3.600 1_1_1_1_15 1_1_1_1_15
31 1_1_1_1_16         16     Cserum 0.000 1.200 1_1_1_1_16 1_1_1_1_16
32 1_1_1_1_16         16     Cserum 5.802 0.600 1_1_1_1_16 1_1_1_1_16
33 1_1_1_1_17         17     Cserum 0.000 2.900 1_1_1_1_17 1_1_1_1_17
34 1_1_1_1_17         17     Cserum 5.802 0.900 1_1_1_1_17 1_1_1_1_17
35 1_1_1_1_18         18     Cserum 0.000 1.200 1_1_1_1_18 1_1_1_1_18
36 1_1_1_1_18         18     Cserum 5.802 0.400 1_1_1_1_18 1_1_1_1_18
37  1_1_1_2_1         19     Cserum 0.000 1.500  1_1_1_2_1  1_1_1_2_1
38  1_1_1_2_1         19     Cserum 5.802 0.400  1_1_1_2_1  1_1_1_2_1
39  1_1_1_2_2         20     Cserum 0.000 3.300  1_1_1_2_2  1_1_1_2_2
40  1_1_1_2_2         20     Cserum 5.802 1.000  1_1_1_2_2  1_1_1_2_2
41  1_1_1_2_3         21     Cserum 0.000 1.800  1_1_1_2_3  1_1_1_2_3
42  1_1_1_2_3         21     Cserum 5.802 0.600  1_1_1_2_3  1_1_1_2_3
43  1_1_1_2_4         22     Cserum 0.000 1.600  1_1_1_2_4  1_1_1_2_4
44  1_1_1_2_4         22     Cserum 5.802 0.700  1_1_1_2_4  1_1_1_2_4
45  1_1_1_2_5         23     Cserum 0.000 4.300  1_1_1_2_5  1_1_1_2_5
46  1_1_1_2_5         23     Cserum 5.802 1.400  1_1_1_2_5  1_1_1_2_5
47  1_1_1_2_6         24     Cserum 0.000 1.700  1_1_1_2_6  1_1_1_2_6
48  1_1_1_2_6         24     Cserum 5.802 1.400  1_1_1_2_6  1_1_1_2_6
49  1_1_1_2_7         25     Cserum 0.000 1.300  1_1_1_2_7  1_1_1_2_7
50  1_1_1_2_7         25     Cserum 5.802 0.400  1_1_1_2_7  1_1_1_2_7
51  1_1_1_2_8         26     Cserum 0.000 3.000  1_1_1_2_8  1_1_1_2_8
52  1_1_1_2_8         26     Cserum 5.802 1.000  1_1_1_2_8  1_1_1_2_8
53  1_1_1_2_9         27     Cserum 0.000 3.100  1_1_1_2_9  1_1_1_2_9
54  1_1_1_2_9         27     Cserum 5.802 1.300  1_1_1_2_9  1_1_1_2_9
55 1_1_1_2_10         28     Cserum 0.000 1.500 1_1_1_2_10 1_1_1_2_10
56 1_1_1_2_10         28     Cserum 5.802 1.200 1_1_1_2_10 1_1_1_2_10
57 1_1_1_2_11         29     Cserum 0.000 3.100 1_1_1_2_11 1_1_1_2_11
58 1_1_1_2_11         29     Cserum 5.802 1.900 1_1_1_2_11 1_1_1_2_11
59 1_1_1_2_12         30     Cserum 0.000 1.900 1_1_1_2_12 1_1_1_2_12
60 1_1_1_2_12         30     Cserum 5.802 0.800 1_1_1_2_12 1_1_1_2_12
61 1_1_1_2_13         31     Cserum 0.000 1.000 1_1_1_2_13 1_1_1_2_13
62 1_1_1_2_13         31     Cserum 5.802 1.100 1_1_1_2_13 1_1_1_2_13
63 1_1_1_2_14         32     Cserum 0.000 1.200 1_1_1_2_14 1_1_1_2_14
64 1_1_1_2_14         32     Cserum 5.802 0.400 1_1_1_2_14 1_1_1_2_14
65 1_1_1_2_15         33     Cserum 0.000 2.500 1_1_1_2_15 1_1_1_2_15
66 1_1_1_2_15         33     Cserum 5.802 0.900 1_1_1_2_15 1_1_1_2_15
67 1_1_1_2_16         34     Cserum 0.000 1.200 1_1_1_2_16 1_1_1_2_16
68 1_1_1_2_16         34     Cserum 5.802 0.400 1_1_1_2_16 1_1_1_2_16
69 1_1_1_2_17         35     Cserum 0.000 2.300 1_1_1_2_17 1_1_1_2_17
70 1_1_1_2_17         35     Cserum 5.802 0.700 1_1_1_2_17 1_1_1_2_17
71 1_1_1_2_18         36     Cserum 0.000 1.500 1_1_1_2_18 1_1_1_2_18
72 1_1_1_2_18         36     Cserum 5.802 0.500 1_1_1_2_18 1_1_1_2_18
73 1_1_1_2_19         37     Cserum 0.000 1.900 1_1_1_2_19 1_1_1_2_19
74 1_1_1_2_19         37     Cserum 5.802 1.100 1_1_1_2_19 1_1_1_2_19
75      1_2_1         38 M_Cbgd_Css 2.200 5.710      1_2_1      1_2_1
76      1_3_1         39 M_Cbgd_Css 2.000 0.925      1_3_1      1_3_1
77      1_4_1         40 M_Cbgd_Css 2.000 1.060      1_4_1      1_4_1
           dataset               Sex       City Train_Test   datatype
1  Decatur M Train              Male    Decatur      Train Individual
2  Decatur M Train              Male    Decatur      Train Individual
3  Decatur M Train              Male    Decatur      Train Individual
4  Decatur M Train              Male    Decatur      Train Individual
5  Decatur M Train              Male    Decatur      Train Individual
6  Decatur M Train              Male    Decatur      Train Individual
7  Decatur M Train              Male    Decatur      Train Individual
8  Decatur M Train              Male    Decatur      Train Individual
9  Decatur M Train              Male    Decatur      Train Individual
10 Decatur M Train              Male    Decatur      Train Individual
11 Decatur M Train              Male    Decatur      Train Individual
12 Decatur M Train              Male    Decatur      Train Individual
13 Decatur M Train              Male    Decatur      Train Individual
14 Decatur M Train              Male    Decatur      Train Individual
15 Decatur M Train              Male    Decatur      Train Individual
16 Decatur M Train              Male    Decatur      Train Individual
17 Decatur M Train              Male    Decatur      Train Individual
18 Decatur M Train              Male    Decatur      Train Individual
19 Decatur F Train            Female    Decatur      Train Individual
20 Decatur F Train            Female    Decatur      Train Individual
21 Decatur F Train            Female    Decatur      Train Individual
22 Decatur F Train            Female    Decatur      Train Individual
23 Decatur F Train            Female    Decatur      Train Individual
24 Decatur F Train            Female    Decatur      Train Individual
25 Decatur F Train            Female    Decatur      Train Individual
26 Decatur F Train            Female    Decatur      Train Individual
27 Decatur F Train            Female    Decatur      Train Individual
28 Decatur F Train            Female    Decatur      Train Individual
29 Decatur F Train            Female    Decatur      Train Individual
30 Decatur F Train            Female    Decatur      Train Individual
31 Decatur F Train            Female    Decatur      Train Individual
32 Decatur F Train            Female    Decatur      Train Individual
33 Decatur F Train            Female    Decatur      Train Individual
34 Decatur F Train            Female    Decatur      Train Individual
35 Decatur F Train            Female    Decatur      Train Individual
36 Decatur F Train            Female    Decatur      Train Individual
37  Decatur M Test              Male    Decatur       Test Individual
38  Decatur M Test              Male    Decatur       Test Individual
39  Decatur M Test              Male    Decatur       Test Individual
40  Decatur M Test              Male    Decatur       Test Individual
41  Decatur M Test              Male    Decatur       Test Individual
42  Decatur M Test              Male    Decatur       Test Individual
43  Decatur M Test              Male    Decatur       Test Individual
44  Decatur M Test              Male    Decatur       Test Individual
45  Decatur M Test              Male    Decatur       Test Individual
46  Decatur M Test              Male    Decatur       Test Individual
47  Decatur M Test              Male    Decatur       Test Individual
48  Decatur M Test              Male    Decatur       Test Individual
49  Decatur M Test              Male    Decatur       Test Individual
50  Decatur M Test              Male    Decatur       Test Individual
51  Decatur M Test              Male    Decatur       Test Individual
52  Decatur M Test              Male    Decatur       Test Individual
53  Decatur M Test              Male    Decatur       Test Individual
54  Decatur M Test              Male    Decatur       Test Individual
55  Decatur F Test            Female    Decatur       Test Individual
56  Decatur F Test            Female    Decatur       Test Individual
57  Decatur F Test            Female    Decatur       Test Individual
58  Decatur F Test            Female    Decatur       Test Individual
59  Decatur F Test            Female    Decatur       Test Individual
60  Decatur F Test            Female    Decatur       Test Individual
61  Decatur F Test            Female    Decatur       Test Individual
62  Decatur F Test            Female    Decatur       Test Individual
63  Decatur F Test            Female    Decatur       Test Individual
64  Decatur F Test            Female    Decatur       Test Individual
65  Decatur F Test            Female    Decatur       Test Individual
66  Decatur F Test            Female    Decatur       Test Individual
67  Decatur F Test            Female    Decatur       Test Individual
68  Decatur F Test            Female    Decatur       Test Individual
69  Decatur F Test            Female    Decatur       Test Individual
70  Decatur F Test            Female    Decatur       Test Individual
71  Decatur F Test            Female    Decatur       Test Individual
72  Decatur F Test            Female    Decatur       Test Individual
73  Decatur F Test            Female    Decatur       Test Individual
74  Decatur F Test            Female    Decatur       Test Individual
75 Paulsboro-Train Mixed (all sexes)  Paulsboro      Train    Summary
76   Horsham-Train Mixed (all sexes)    Horsham      Train    Summary
77 Warminster-Test Mixed (all sexes) Warminster       Test    Summary
             variable            Dataset Time.desc               Dataset.Time
1   Decatur M Train 1  Decatur M Train 1       T=0      Decatur M Train 1.T=0
2   Decatur M Train 1  Decatur M Train 1   T=5.802  Decatur M Train 1.T=5.802
3   Decatur M Train 2  Decatur M Train 2       T=0      Decatur M Train 2.T=0
4   Decatur M Train 2  Decatur M Train 2   T=5.802  Decatur M Train 2.T=5.802
5   Decatur M Train 3  Decatur M Train 3       T=0      Decatur M Train 3.T=0
6   Decatur M Train 3  Decatur M Train 3   T=5.802  Decatur M Train 3.T=5.802
7   Decatur M Train 4  Decatur M Train 4       T=0      Decatur M Train 4.T=0
8   Decatur M Train 4  Decatur M Train 4   T=5.802  Decatur M Train 4.T=5.802
9   Decatur M Train 5  Decatur M Train 5       T=0      Decatur M Train 5.T=0
10  Decatur M Train 5  Decatur M Train 5   T=5.802  Decatur M Train 5.T=5.802
11  Decatur M Train 6  Decatur M Train 6       T=0      Decatur M Train 6.T=0
12  Decatur M Train 6  Decatur M Train 6   T=5.802  Decatur M Train 6.T=5.802
13  Decatur M Train 7  Decatur M Train 7       T=0      Decatur M Train 7.T=0
14  Decatur M Train 7  Decatur M Train 7   T=5.802  Decatur M Train 7.T=5.802
15  Decatur M Train 8  Decatur M Train 8       T=0      Decatur M Train 8.T=0
16  Decatur M Train 8  Decatur M Train 8   T=5.802  Decatur M Train 8.T=5.802
17  Decatur M Train 9  Decatur M Train 9       T=0      Decatur M Train 9.T=0
18  Decatur M Train 9  Decatur M Train 9   T=5.802  Decatur M Train 9.T=5.802
19 Decatur F Train 10 Decatur F Train 10       T=0     Decatur F Train 10.T=0
20 Decatur F Train 10 Decatur F Train 10   T=5.802 Decatur F Train 10.T=5.802
21 Decatur F Train 11 Decatur F Train 11       T=0     Decatur F Train 11.T=0
22 Decatur F Train 11 Decatur F Train 11   T=5.802 Decatur F Train 11.T=5.802
23 Decatur F Train 12 Decatur F Train 12       T=0     Decatur F Train 12.T=0
24 Decatur F Train 12 Decatur F Train 12   T=5.802 Decatur F Train 12.T=5.802
25 Decatur F Train 13 Decatur F Train 13       T=0     Decatur F Train 13.T=0
26 Decatur F Train 13 Decatur F Train 13   T=5.802 Decatur F Train 13.T=5.802
27 Decatur F Train 14 Decatur F Train 14       T=0     Decatur F Train 14.T=0
28 Decatur F Train 14 Decatur F Train 14   T=5.802 Decatur F Train 14.T=5.802
29 Decatur F Train 15 Decatur F Train 15       T=0     Decatur F Train 15.T=0
30 Decatur F Train 15 Decatur F Train 15   T=5.802 Decatur F Train 15.T=5.802
31 Decatur F Train 16 Decatur F Train 16       T=0     Decatur F Train 16.T=0
32 Decatur F Train 16 Decatur F Train 16   T=5.802 Decatur F Train 16.T=5.802
33 Decatur F Train 17 Decatur F Train 17       T=0     Decatur F Train 17.T=0
34 Decatur F Train 17 Decatur F Train 17   T=5.802 Decatur F Train 17.T=5.802
35 Decatur F Train 18 Decatur F Train 18       T=0     Decatur F Train 18.T=0
36 Decatur F Train 18 Decatur F Train 18   T=5.802 Decatur F Train 18.T=5.802
37  Decatur M Test 19  Decatur M Test 19       T=0      Decatur M Test 19.T=0
38  Decatur M Test 19  Decatur M Test 19   T=5.802  Decatur M Test 19.T=5.802
39  Decatur M Test 20  Decatur M Test 20       T=0      Decatur M Test 20.T=0
40  Decatur M Test 20  Decatur M Test 20   T=5.802  Decatur M Test 20.T=5.802
41  Decatur M Test 21  Decatur M Test 21       T=0      Decatur M Test 21.T=0
42  Decatur M Test 21  Decatur M Test 21   T=5.802  Decatur M Test 21.T=5.802
43  Decatur M Test 22  Decatur M Test 22       T=0      Decatur M Test 22.T=0
44  Decatur M Test 22  Decatur M Test 22   T=5.802  Decatur M Test 22.T=5.802
45  Decatur M Test 23  Decatur M Test 23       T=0      Decatur M Test 23.T=0
46  Decatur M Test 23  Decatur M Test 23   T=5.802  Decatur M Test 23.T=5.802
47  Decatur M Test 24  Decatur M Test 24       T=0      Decatur M Test 24.T=0
48  Decatur M Test 24  Decatur M Test 24   T=5.802  Decatur M Test 24.T=5.802
49  Decatur M Test 25  Decatur M Test 25       T=0      Decatur M Test 25.T=0
50  Decatur M Test 25  Decatur M Test 25   T=5.802  Decatur M Test 25.T=5.802
51  Decatur M Test 26  Decatur M Test 26       T=0      Decatur M Test 26.T=0
52  Decatur M Test 26  Decatur M Test 26   T=5.802  Decatur M Test 26.T=5.802
53  Decatur M Test 27  Decatur M Test 27       T=0      Decatur M Test 27.T=0
54  Decatur M Test 27  Decatur M Test 27   T=5.802  Decatur M Test 27.T=5.802
55  Decatur F Test 28  Decatur F Test 28       T=0      Decatur F Test 28.T=0
56  Decatur F Test 28  Decatur F Test 28   T=5.802  Decatur F Test 28.T=5.802
57  Decatur F Test 29  Decatur F Test 29       T=0      Decatur F Test 29.T=0
58  Decatur F Test 29  Decatur F Test 29   T=5.802  Decatur F Test 29.T=5.802
59  Decatur F Test 30  Decatur F Test 30       T=0      Decatur F Test 30.T=0
60  Decatur F Test 30  Decatur F Test 30   T=5.802  Decatur F Test 30.T=5.802
61  Decatur F Test 31  Decatur F Test 31       T=0      Decatur F Test 31.T=0
62  Decatur F Test 31  Decatur F Test 31   T=5.802  Decatur F Test 31.T=5.802
63  Decatur F Test 32  Decatur F Test 32       T=0      Decatur F Test 32.T=0
64  Decatur F Test 32  Decatur F Test 32   T=5.802  Decatur F Test 32.T=5.802
65  Decatur F Test 33  Decatur F Test 33       T=0      Decatur F Test 33.T=0
66  Decatur F Test 33  Decatur F Test 33   T=5.802  Decatur F Test 33.T=5.802
67  Decatur F Test 34  Decatur F Test 34       T=0      Decatur F Test 34.T=0
68  Decatur F Test 34  Decatur F Test 34   T=5.802  Decatur F Test 34.T=5.802
69  Decatur F Test 35  Decatur F Test 35       T=0      Decatur F Test 35.T=0
70  Decatur F Test 35  Decatur F Test 35   T=5.802  Decatur F Test 35.T=5.802
71  Decatur F Test 36  Decatur F Test 36       T=0      Decatur F Test 36.T=0
72  Decatur F Test 36  Decatur F Test 36   T=5.802  Decatur F Test 36.T=5.802
73  Decatur F Test 37  Decatur F Test 37       T=0      Decatur F Test 37.T=0
74  Decatur F Test 37  Decatur F Test 37   T=5.802  Decatur F Test 37.T=5.802
75 Paulsboro-Train 38 Paulsboro-Train 38     T=2.2   Paulsboro-Train 38.T=2.2
76   Horsham-Train 39   Horsham-Train 39       T=2       Horsham-Train 39.T=2
77 Warminster-Test 40 Warminster-Test 40       T=2     Warminster-Test 40.T=2
#Multicheck plot

# Split Steady State Group into different populations for boxplot grouping
#df_check[df_check$Time.desc == "SteadyState" & grepl("Lubeck",df_check$Dataset),]$Time.desc <- "Lubeck"
#df_check[df_check$Time.desc == "SteadyState" & grepl("Little Hocking",df_check$Dataset),]$Time.desc <- "Little Hocking"

Modify aesthetics lookup table for boxplots

##  additional source aesthetic lookup table for grey-scale time (years);  merged legends save space on plotting output
times <- df_check%>% select(Time.desc, Time) %>%  unique () %>% 
  mutate(rank = rank(Time) , grey = grey.colors(start=1,end=0.4, n = n()),
         alpha = (rank)/8) %>% 
  select(-Time)
 
df_check <- df_check %>% mutate (legend_label = (paste0(City, "\n", Time.desc ) )) # add legend-labels
aes_lut <- df_check %>% 
  select(City, Train_Test, datatype,Time, Time.desc, legend_label) %>% unique () %>%
   left_join(aes_lut[, c("City", "cols")], by = "City") %>% ungroup () %>% unique ()%>%
   left_join (times, by = "Time.desc") %>% 
   arrange(datatype, City, Train_Test, Time)    %>% 
   mutate(alpha = if_else(City == "Horsham", alpha/2, alpha)) %>% # otherwise too dark with this color
  mutate_if(is.factor, as.character) 

Decatur boxplots

Changed grey start to 1 instead of 0.8, end at 0.6 instead of 0.4. Changed shape of symbols so they are filled.

##EF

df_decat  <- df_check %>%   
  filter(City == "Decatur" & Train_Test %in% c ("Train", "Test")) %>% 
  mutate(panel = ordered (Train_Test, levels = c ("Train", "Test"), 
                          labels = c("E: PFNA Decatur Train", "F: PFNA Decatur Test") ))

aes_lut_df_df_decat <- aes_lut %>% 
  filter(City == "Decatur" & Train_Test %in% c ("Train", "Test")) %>% 
  mutate_if(is.factor, as.character) 

source( paste0(gsub(basename(here()), 'shared_functions', here()), '/plot_sum_boxplot.r'))


plt_train <- plot_sum_boxplot   (dframe = df_decat, aes_lut= aes_lut_df_df_decat, facets = TRUE , pfas_nom = pfas_name     ) 
print(plt_train)

ggsave(here ("output-plots",paste0( sa,"DecaturTrainTestboxplot",pfas_name,".pdf")),plt_train,dpi=600)
Saving 6.5 x 3.5 in image
ggsave(here ("output-plots",paste0( sa,"DecaturTrainTestboxplot",pfas_name,".png")),plt_train,dpi=600)
Saving 6.5 x 3.5 in image

All boxplots

Changed grey start to 1 instead of 0.8, end at 0.6 instead of 0.4. Added shapes and fills to data points.

lets <- LETTERS;
names(lets)[1:(length(unique(df_check$dataset))-4)]<-as.character(unique(df_check$dataset))[5:length(unique(df_check$dataset))]

for (d in unique(df_check$dataset)) { # d = unique(df_check$dataset)[11]
    ddset <- df_check %>%    
    filter(dataset == d) 
    
    aes_lut_ddset <- ddset %>% select(legend_label,  City,Train_Test,datatype, Time.desc  ) %>% unique () %>% inner_join(aes_lut)
      
    gt <- ifelse(is.na(lets[d]),d,paste0(lets[d],": ", d))
    plt <- plot_sum_boxplot(dframe = ddset, aes_lut= aes_lut_ddset, gtitle= gt, facets = FALSE, pfas_nom = pfas_name)
     
  print(plt)
  ggsave(here ("output-plots",
                paste0( sa, d,"-boxplot-", 
                pfas_name,".pdf")) ,
         plt,dpi=600)
    ggsave(here ("output-plots",
                paste0( sa, d,"-boxplot-", 
                pfas_name,".png")) ,
         plt,dpi=600)


}
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")
Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")

Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")

Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")

Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")

Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")

Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")

Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image

### make Training plot  

df_d_trt <- df_check %>%   
     filter( (Train_Test == "Train") & ((Output_Var == "M_Cbgd_Css") | (Output_Var == "M_Cserum"))) %>%
     mutate_if(is.factor, as.character) %>%  # drop factor levels unused
     mutate(Dataset.Time = factor(Dataset.Time)) 
 

 aes_lut_df_d_trt <-  df_d_trt %>% select(City, datatype,Time, Time.desc, legend_label) %>% 
   inner_join(aes_lut  ) %>% 
   select(-Train_Test) %>% ungroup () %>% unique ()  
Joining, by = c("City", "datatype", "Time", "Time.desc", "legend_label")
plt_train <-    plot_sum_boxplot(dframe = df_d_trt, aes_lut= aes_lut_df_d_trt,   
                                 gtitle="A: Summary Data - Train" , facets = FALSE, pfas_nom = pfas_name )
  print(plt_train)

  ggsave(here ("output-plots", paste0( sa, "SummaryTrainDataboxplot",pfas_name,".pdf")), plt_train,dpi=600)
Saving 6.5 x 3.5 in image
  ggsave(here ("output-plots", paste0( sa, "SummaryTrainDataboxplot",pfas_name,".png")), plt_train,dpi=600)
Saving 6.5 x 3.5 in image
###  make Test plot
df_d_test <- df_check %>%   
    filter((Train_Test == "Test") & 
             ((Output_Var == "M_Cbgd_Css") | (Output_Var == "M_Cserum")))  %>%
     mutate_if(is.factor, as.character) %>%  # drop factor levels unused
     mutate(Dataset.Time = factor(Dataset.Time)) 

aes_lut_df_d_test <-  df_d_test %>% select(City, datatype,Time, Time.desc, legend_label) %>% 
   inner_join(aes_lut  ) %>% 
   select(-Train_Test) %>% ungroup () %>% unique ()  
Joining, by = c("City", "datatype", "Time", "Time.desc", "legend_label")
plt_test <- plot_sum_boxplot(dframe = df_d_test, aes_lut= aes_lut_df_d_test, 
                             gtitle="B: Summary Data - Test", facets = FALSE, pfas_nom = pfas_name)
  print(plt_test)

  ggsave(here ("output-plots",paste0( sa, "SummaryTestDataboxplot",pfas_name,".pdf")), plt_test,dpi=600)  
Saving 6.5 x 3.5 in image
    ggsave(here ("output-plots",paste0( sa, "SummaryTestDataboxplot",pfas_name,".png")), plt_test,dpi=600)  
Saving 6.5 x 3.5 in image

PFNA

Background posteriors

Shows shift in background estimate.

gmscale<-0.8

dat <- multicheck$parms.samp[,grep("M_ln_Cbgd",names(multicheck$parms.samp))]
datasetnames <- as.character(unique(calibdata$dataset))
datasetnames <- gsub(" Train","-Train",datasetnames)
datasetnames <- gsub(" Test","-Train",datasetnames)
datasetnames <- gsub(" M","",datasetnames)
datasetnames <- gsub(" F","",datasetnames)
datasetnames<-datasetnames[!duplicated(datasetnames)]
names(dat) <- datasetnames
dat <- dat[,grep("Train",names(dat))]
dat.df <- pivot_longer(dat,1:ncol(dat))
dat.df <- rbind(dat.df,
                data.frame(name="Prior",value=rnorm(5000,m=log(gmscale),sd=0.4055)))
dat.df$name <- factor(dat.df$name,levels=rev(
                        c("Prior",datasetnames[grep("Train",datasetnames)])))
dat.df$value <- exp(dat.df$value)

p<-ggplot(dat.df)+
  #geom_violin(aes(x=name,y=value,fill=name=="Prior"))+
  geom_boxplot(aes(x=name,y=value,fill=name=="Prior"),outlier.shape=NA)+
  scale_y_log10()+coord_flip()+
      scale_fill_manual(name=NULL, 
                    values=c("#009988", "#EE7733" ))+
  theme_classic() +  
  geom_hline(yintercept = gmscale,color="grey")+
  theme(legend.position="none",
      panel.background = element_rect(color="black",size=1))+
  ylab("Posterior shift in Background Concentration")

print(p)

ggsave(here ("output-plots",paste0( sa, "PFNA_GM_Cbgd.pdf")) ,p,dpi=600)
Saving 5 x 6 in image
ggsave(here ("output-plots",paste0( sa, "PFNA_GM_Cbgd.png")) ,p,dpi=600)
Saving 5 x 6 in image

Half-life

For PFNA, the population GM of the half-life has a posterior distribution that is narrower than the prior, with a posterior median (95% CI) estimate of 3.06 (2.16-4.37) years. The population GSD posterior is larger than the prior at 1.47(1.44-1.75).

dat <- multicheck$parms.samp[,c("M_ln_k.1.","V_ln_k.1.", "M_ln_Vd.1.", "SD_ln_Vd.1.")]
names(dat) <- c("M_ln_k(1)","V_ln_k(1)", "M_ln_Vd(1)", "SD_ln_Vd(1)")
  
set.seed(3.14159)
dat$z_ln_k <- rnorm(nrow(dat))
dat$z_ln_Vd <- rnorm(nrow(dat))
dat %>% rename_()
dat$ln_k_i <- dat$`M_ln_k(1)` + sqrt(dat$`V_ln_k(1)`)*dat$z_ln_k
dat$ln_Vd_i <- dat$`M_ln_Vd(1)`+ dat$`SD_ln_Vd(1)`*dat$z_ln_Vd
linmod <- lm(ln_Vd_i ~ ln_k_i,data=dat)
ggplot(dat) + geom_point(aes(ln_k_i,ln_Vd_i)) + 
  labs(subtitle=paste("Adj R2 =",signif(summary(linmod)$adj.r.squared,2)))

Check normality

qqnorm(dat$ln_k_i,main="ln k Q-Q Normal")
qqline(dat$ln_k_i,col="red")

plot(ecdf(dat$ln_k_i))
x <- seq(-3,1,0.01)
m_ln_k_i <-   mean(dat$ln_k_i)
sd_ln_k_i <- sd(dat$ln_k_i)
lines(x,pnorm(x,mean=m_ln_k_i,sd=sd_ln_k_i),col="red")
text(m_ln_k_i-2*sd_ln_k_i,0.9,paste("m =",signif(m_ln_k_i,4),"\nsd =",signif(sd_ln_k_i,4)))

qqnorm(dat$ln_Vd_i,main="ln Vd Q-Q Normal")
qqline(dat$ln_Vd_i,col="red")

plot(ecdf(dat$ln_Vd_i))
x <- seq(-3,1,0.01)
m_ln_Vd_i <- mean(dat$ln_Vd_i)
sd_ln_Vd_i <- sd(dat$ln_Vd_i)

lines(x,pnorm(x,mean=m_ln_Vd_i,sd=sd_ln_Vd_i),col="red")
text(m_ln_Vd_i-2*sd_ln_Vd_i,0.9,paste("m =",signif(m_ln_Vd_i,4),"\nsd =",signif(sd_ln_Vd_i,4)))

Calculate table values for individual-level

hl_i <- log(2)/ exp(dat$ln_k_i) # individual half-life 
med_hl_i <- paste(signif (median (hl_i), 3)) # median of individual half-life
ci_med_hl_i <-   paste(signif (quantile(hl_i, prob=c(0.025,0.975)), 3),collapse="-") # 95ci med individual halflife
ci98_med_hl_i <-   paste(signif (quantile(hl_i, prob=c(0.01,0.99)), 3),collapse="-") # 98ci med individual halflife
gm_hl_i <- paste(signif (exp(mean(log(hl_i))), 3)) # gm (which should be really close)
gsd_hl_i <- paste(signif (exp(sd(log(hl_i))), 3)) # gsd individual

med_Vd_i <- paste(signif (median(exp(dat$ln_Vd_i)), 3)) # median individual Vd
ci_med_Vd_i <-paste(signif (quantile(exp(dat$ln_Vd_i), prob=c(0.025,0.975)), 3),collapse="-") # 95ci med individual Vd
ci98_med_Vd_i <-paste(signif (quantile(exp(dat$ln_Vd_i), prob=c(0.01,0.99)), 3),collapse="-") # 98ci med individual Vd
gm_vd_i <- paste(signif (exp(mean(dat$ln_Vd_i)), 3)) # gm (which should be really close)
gsd_vd_i<- paste(signif (exp(sd(dat$ln_Vd_i)), 3)) # gsd indiv

med_CL_i <- paste(signif (median(exp(dat$ln_Vd_i+dat$ln_k_i)), 3)) # median individual CL
ci_med_CL_i <-paste(signif (quantile(exp(dat$ln_Vd_i+dat$ln_k_i), prob=c(0.025,0.975)), 3),collapse="-") # 95ci med individual CL
ci98_med_CL_i <-paste(signif (quantile(exp(dat$ln_Vd_i+dat$ln_k_i), prob=c(0.01,0.99)), 3),collapse="-") # 98ci med individual CL
gm_CL_i <- paste(signif (exp(mean(dat$ln_Vd_i+dat$ln_k_i)), 3)) # gm (which should be really close)
gsd_CL_i<- paste(signif (exp(sd(dat$ln_Vd_i+dat$ln_k_i)), 3)) # gsd indiv
PFNA_priors <- data.frame(
  halflife_GM= log(2)/rlnorm(50000,
                             meanlog=-1.80181,sdlog=0.4055))
M_k <- exp(as.numeric(dat$`M_ln_k(1)`))
PFNA_halflife_GM <- log(2)/M_k

PFNA_hlgm_pr_med <- signif(median(PFNA_priors$halflife_GM,3))
PFNA_hlgm_pr_med_95ci <-paste(signif(quantile(PFNA_priors$halflife_GM,
                                            prob=c(0.025,0.975)),
                                   3),
                            collapse="-")

PFNA_hl_median_gm <- signif(median(PFNA_halflife_GM),3)
PFNA_hl_median_gm_95ci <- paste(signif(quantile(PFNA_halflife_GM,
                                            prob=c(0.025,0.975)),3),collapse="-")

p<-ggplot()+
  stat_density(aes(halflife_GM, color = "Prior"),data=PFNA_priors,geom="line",size=2)+
  stat_density(aes(PFNA_halflife_GM,stat(density),color="Posterior"),geom="line",size=1.5)+
  xlim(0,15)+
  labs(title = bquote("E: PFNA"~T[1/2]~"Population GM")  ,
       subtitle=paste("Posterior Median (95% CI): ",
                      PFNA_hl_median_gm," (",
                      PFNA_hl_median_gm_95ci,
                      ")",sep=""))+
 xlab(bquote("Population GM"~T[1/2]~"(yrs)")) +
  scale_color_manual(name=NULL, 
                     values=c(Prior="#009988", Posterior="#EE7733" )) + 
  theme_classic() +  
  theme(legend.title = element_blank(),legend.position=c(0.8,0.7),
      panel.background = element_rect(color="black",size=1),
      legend.background = element_rect(fill="transparent", color=NA))
print(p)
Warning: Removed 41 rows containing non-finite values (stat_density).

ggsave(here ("output-plots", paste0( sa, "PFNA_hl_gm.pdf")) ,p,dpi=600)
Saving 4 x 2.5 in image
Warning: Removed 41 rows containing non-finite values (stat_density).
ggsave(here ("output-plots", paste0( sa, "PFNA_hl_gm.png")) ,p,dpi=600)
Saving 4 x 2.5 in image
Warning: Removed 41 rows containing non-finite values (stat_density).
PFNA_priors$halflife_GSD =  exp(sqrt(exp(rnorm(50000,m=log(0.2000),sd=log(1.275))))) 
PFNA_halflife_GSD <- exp(sqrt(dat$`V_ln_k(1)`))

PFNA_hlgsd_pr_med <- signif(median(PFNA_priors$halflife_GSD,3))
PFNA_hlgsd_pr_med_95ci <-paste(signif(quantile(PFNA_priors$halflife_GSD,
                                            prob=c(0.025,0.975)),
                                   3),
                            collapse="-")
PFNA_hl_gsd_med <- signif(median(PFNA_halflife_GSD),3)
PFNA_hl_gsd_med_95ci <- paste(signif(quantile(PFNA_halflife_GSD,
                                            prob=c(0.025,0.975)),3),collapse="-")
p<-ggplot()+
  stat_density(aes(halflife_GSD, color = "Prior"),data=PFNA_priors,geom="line",size=2)+
  stat_density(aes(PFNA_halflife_GSD,stat(density), color = "Posterior"),geom="line",size=1.5)+
  xlim(1,3)+
  labs(title = bquote("F: PFNA"~T[1/2]~"Population GSD"), 
       subtitle=paste("Posterior Median (95% CI): ",
                      PFNA_hl_gsd_med," (",
                      PFNA_hl_gsd_med_95ci,
                      ")",sep=""))+
  xlab(bquote("Population GSD"~T[1/2]))+
  scale_color_manual(name=NULL, 
                     values=c(Prior="#009988", Posterior="#EE7733" )) + 
   theme_classic() +  
  theme(legend.title = element_blank(),legend.position=c(0.8,0.7),
      panel.background = element_rect(color="black",size=1),
      legend.background = element_rect(fill="transparent", color=NA))
print(p)

ggsave(here ("output-plots", paste0( sa, "PFNA_hl_gsd.pdf")), p,dpi=600)
ggsave(here ("output-plots", paste0( sa, "PFNA_hl_gsd.png")), p,dpi=600)

Distribution Volume

For PFNA, the data were not particularly informative, but slightly increased the estimate of the median to 0.308(0.223-0.548) slightly. They were not informative as to the population GSD, with the posterior distributions essentially unchanged from the priors.

PFNA_priors$Vd_GM <- rlnorm(50000,
                             meanlog=-1.77196,
                             sdlog=0.2624)
PFNA_Vd_GM <- exp(dat$`M_ln_Vd(1)`)

 

PFNA_vd_gm_pr_med <- signif(median(PFNA_priors$Vd_GM,3))
PFNA_vd_gm_pr_med_95ci <- paste(signif(quantile(PFNA_priors$Vd_GM,
                                            prob=c(0.025,0.975)), 3), collapse="-")
PFNA_vd_gm_med <- signif(median(PFNA_Vd_GM),3)
PFNA_vd_gm_med_95ci <- paste(signif(quantile(PFNA_Vd_GM,
                                            prob=c(0.025,0.975)),3),collapse="-")

p<-ggplot()+
  stat_density(aes(Vd_GM, color = "Prior"),data=PFNA_priors,geom="line",size=2)+
  stat_density(aes(PFNA_Vd_GM,stat(density), color = "Posterior"),geom="line",size=1.5)+
  xlim(0,1)+labs(title = bquote("E: PFNA"~V[d]~"Population GM"),
                 subtitle=paste("Posterior Median (95% CI): ",
                                PFNA_vd_gm_med," (", 
                                PFNA_vd_gm_med_95ci,")",sep=""))+
   xlab(bquote("Population GM"~V[d]~"(l/kg)"))+
  scale_color_manual(name=NULL, 
                     values=c(Prior="#009988", Posterior="#EE7733" ))   +  
  theme_classic() +  
  theme(legend.title = element_blank(),legend.position=c(0.8,0.7),
      panel.background = element_rect(color="black",size=1),
      legend.background = element_rect(fill="transparent", color=NA))
print(p)

ggsave(here ("output-plots",paste0( sa, "PFNA_vd_gm.pdf")), p,dpi=600)
ggsave(here ("output-plots",paste0( sa, "PFNA_vd_gm.png")), p,dpi=600)
PFNA_priors$Vd_GSD = exp(abs(rnorm(50000,sd=0.17)))
PFNA_Vd_GSD <- exp(dat$`SD_ln_Vd(1)`)

PFNA_vd_gsd_pr_med <- signif(median(PFNA_priors$Vd_GSD,3))
PFNA_vd_gsd_pr_med_95ci <- paste(signif(quantile(PFNA_priors$Vd_GSD,
                                            prob=c(0.025,0.975)), 3), collapse="-")

PFNA_vd_gsd_med <- signif(median(PFNA_Vd_GSD),3)
PFNA_vd_gsd_med_95ci <- paste(signif(quantile(PFNA_Vd_GSD,
                                            prob=c(0.025,0.975)),3),collapse="-")

p<-ggplot()+
  stat_density(aes(Vd_GSD, color = "Prior"),data=PFNA_priors,geom="line",size=2)+
  stat_density(aes(PFNA_Vd_GSD,stat(density), color = "Posterior"),geom="line",size=1.5)+
  xlim(1,3)+
  labs(title = bquote("F: PFNA"~V[d]~"Population GSD "),
       subtitle=paste("Posterior Median (95% CI): ",
                      PFNA_vd_gsd_med," (",
                      PFNA_vd_gsd_med_95ci,
                      ")",sep=""))+
  xlab(bquote("Population GSD"~V[d]))+
  scale_color_manual(name=NULL, 
                     values=c(Prior="#009988", Posterior="#EE7733" )) +  
  theme_classic() +  
  theme(legend.title = element_blank(),legend.position=c(0.8,0.7),
      panel.background = element_rect(color="black",size=1),
      legend.background = element_rect(fill="transparent", color=NA))
print(p)

ggsave(here ("output-plots",paste0( sa, "PFNA_vd_gsd.pdf")), p,dpi=600)
ggsave(here ("output-plots",paste0( sa, "PFNA_vd_gsd.png")), p,dpi=600)

Clearance

Cl is k * Vd

PFNA_priors$CL_GM <- PFNA_priors$Vd_GM * (log(2)/PFNA_priors$halflife_GM)
PFNA_CL_GM <- exp(dat$`M_ln_Vd(1)` + dat$`M_ln_k(1)`)

PFNA_cl_gm_pr_med <- signif(median(PFNA_priors$CL_GM,3))
PFNA_cl_gm_pr_med_95ci <- paste(signif(quantile(PFNA_priors$CL_GM,
                                            prob=c(0.025,0.975)), 3), collapse="-")
PFNA_cl_gm_med <- signif(median(PFNA_CL_GM),3)
PFNA_cl_gm_med_95ci <- paste(signif(quantile(PFNA_CL_GM,
                                            prob=c(0.025,0.975)),3),collapse="-")

p<-ggplot()+
  stat_density(aes(CL_GM, color = "Prior"),data=PFNA_priors,geom="line",size=2)+
  stat_density(aes(PFNA_CL_GM,stat(density), color = "Posterior"),geom="line",size=1.5)+
  xlim(0,0.25)+labs(title = "C: PFNA Clearance Pop. GM ",subtitle=paste("Posterior Median (95% CI): ",
                                                                    PFNA_cl_gm_med," (",
                                                                    PFNA_cl_gm_med_95ci,
                                                                    ")",sep=""))+
  xlab("Pop. GM CL (l/(kg-yr))")+
  scale_color_manual(name=NULL, 
                     values=c(Prior="#009988", Posterior="#EE7733" )) +  
  theme_classic() +  
  theme(legend.title = element_blank(),legend.position=c(0.8,0.7),
      panel.background = element_rect(color="black",size=1),
      legend.background = element_rect(fill="transparent", color=NA))
print(p)

ggsave(here ("output-plots",paste0( sa, "PFNA_CL_gm.pdf")) ,p,dpi=600)
ggsave(here ("output-plots",paste0( sa, "PFNA_CL_gm.png")) ,p,dpi=600)
PFNA_priors$CL_GSD = exp(sqrt(log(PFNA_priors$Vd_GSD)^2 + 
  log(PFNA_priors$halflife_GSD)^2))
PFNA_CL_GSD <- exp(sqrt(log(PFNA_Vd_GSD)^2 + 
  log(PFNA_halflife_GSD)^2))

PFNA_CL_gsd_pr_med <- signif(median(PFNA_priors$CL_GSD,3))
PFNA_CL_gsd_pr_med_95ci <- paste(signif(quantile(PFNA_priors$CL_GSD,
                                            prob=c(0.025,0.975)), 3), collapse="-")

PFNA_CL_gsd_med <- signif(median(PFNA_CL_GSD),3)
PFNA_CL_gsd_med_95ci <- paste(signif(quantile(PFNA_CL_GSD,
                                            prob=c(0.025,0.975)),3),collapse="-")

p<-ggplot()+
  stat_density(aes(CL_GSD, color = "Prior"),data=PFNA_priors,geom="line",size=2)+
  stat_density(aes(PFNA_CL_GSD,stat(density), color = "Posterior"),geom="line",size=1.5)+
  xlim(1,3)+
  labs(title = bquote("H: PFNA"~CL~"Population GSD "),
       subtitle=paste("Posterior Median (95% CI): ",
                      PFNA_CL_gsd_med," (",
                      PFNA_CL_gsd_med_95ci,
                      ")",sep=""))+
  xlab(bquote("Population GSD"~CL))+
  scale_color_manual(name=NULL, 
                     values=c(Prior="#009988", Posterior="#EE7733" )) + 
  theme_classic() +  
  theme(legend.title = element_blank(),legend.position=c(0.8,0.7),
      panel.background = element_rect(color="black",size=1),
      legend.background = element_rect(fill="transparent", color=NA))
print(p)

ggsave(here ("output-plots",paste0( sa,"PFNA_CL_gsd.pdf")) ,p,dpi=600)
ggsave(here ("output-plots",paste0( sa,"PFNA_CL_gsd.png")) ,p,dpi=600)

Table significant digit values

PFNA_hlgm_pr_med <- paste(signif(PFNA_hlgm_pr_med, 3))
PFNA_hl_median_gm<- paste(signif(PFNA_hl_median_gm, 3))
PFNA_hlgsd_pr_med<- paste(signif(PFNA_hlgsd_pr_med, 3))
PFNA_hl_gsd_med<- paste(signif(PFNA_hl_gsd_med, 3))
PFNA_vd_gm_pr_med<- paste(signif(PFNA_vd_gm_pr_med, 3))
PFNA_vd_gm_med<- paste(signif(PFNA_vd_gm_med, 3))
PFNA_vd_gsd_pr_med<- paste(signif(PFNA_vd_gsd_pr_med, 3))
PFNA_vd_gsd_med<- paste(signif(PFNA_vd_gsd_med, 3))
PFNA_cl_gm_pr_med<- paste(signif(PFNA_cl_gm_pr_med, 3))
PFNA_cl_gm_med<- paste(signif(PFNA_cl_gm_med, 3))

Population median estimates [95% CI]

Parameter Prior GM Posterior GM Prior GSD Posterior GSD
Half-life (years) 4.2 2.35 1.56 1.53
HL [95% CI] [1.89-9.37] [1.65-3.16] [1.42-1.77] [1.4-1.7]
Volume of distribution 0.17 0.186 1.12 1.12
\(V_D\) [95% CI] [0.102-0.284] [0.113-0.302] [1.01-1.46] [1.01-1.51]
Clearance 0.028 0.0559
\(CL\) [95% CI] [0.0108-0.0727] [0.0327-0.0932] [] []

Individual Posterior estimates

Parameter median GM [95% CI] [[98% CI]] GM calculator input GSD individual
Half-life (years) 2.27 [ 0.826-5.36 ] [[ 0.758-5.94 ]] 2.27 1.61
Volume of distribution \(V_D\) 0.183 [ 0.0998-0.324 ] [[ 0.085-0.398 ]] 0.185 1.35
Clearance (L/kg-yr) 0.0573 [ 0.0188-0.163 ] [[ 0.0165-0.199 ]] 0.0563 1.7
─ Session info ───────────────────────────────────────────────────────────────
 setting  value                                      
 version  R version 3.6.3 (2020-02-29)               
 os       Red Hat Enterprise Linux Server 7.9 (Maipo)
 system   x86_64, linux-gnu                          
 ui       X11                                        
 language (EN)                                       
 collate  en_US.UTF-8                                
 ctype    en_US.UTF-8                                
 tz       America/New_York                           
 date     2022-01-23                                 

─ Packages ───────────────────────────────────────────────────────────────────
 package     * version  date       lib source        
 assertthat    0.2.1    2019-03-21 [2] CRAN (R 3.6.3)
 backports     1.2.1    2020-12-09 [2] CRAN (R 3.6.3)
 bayesplot   * 1.8.0    2021-01-10 [2] CRAN (R 3.6.3)
 broom         0.7.5    2021-02-19 [2] CRAN (R 3.6.3)
 bslib         0.2.4    2021-01-25 [2] CRAN (R 3.6.3)
 cachem        1.0.4    2021-02-13 [2] CRAN (R 3.6.3)
 callr         3.5.1    2020-10-13 [2] CRAN (R 3.6.3)
 cellranger    1.1.0    2016-07-27 [2] CRAN (R 3.6.3)
 cli           2.3.1    2021-02-23 [2] CRAN (R 3.6.3)
 coda        * 0.19-4   2020-09-30 [2] CRAN (R 3.6.3)
 codetools     0.2-18   2020-11-04 [2] CRAN (R 3.6.3)
 colorspace    2.0-0    2020-11-11 [2] CRAN (R 3.6.3)
 crayon        1.4.1    2021-02-08 [2] CRAN (R 3.6.3)
 DBI           1.1.1    2021-01-15 [2] CRAN (R 3.6.3)
 dbplyr        2.1.0    2021-02-03 [2] CRAN (R 3.6.3)
 debugme       1.1.0    2017-10-22 [2] CRAN (R 3.6.3)
 desc          1.3.0    2021-03-05 [2] CRAN (R 3.6.3)
 devtools      2.3.2    2020-09-18 [2] CRAN (R 3.6.3)
 digest        0.6.27   2020-10-24 [2] CRAN (R 3.6.3)
 dplyr       * 1.0.5    2021-03-05 [2] CRAN (R 3.6.3)
 ellipsis      0.3.1    2020-05-15 [2] CRAN (R 3.6.3)
 evaluate      0.14     2019-05-28 [2] CRAN (R 3.6.3)
 fansi         0.4.2    2021-01-15 [2] CRAN (R 3.6.3)
 farver        2.1.0    2021-02-28 [2] CRAN (R 3.6.3)
 fastmap       1.1.0    2021-01-25 [2] CRAN (R 3.6.3)
 forcats     * 0.5.1    2021-01-27 [2] CRAN (R 3.6.3)
 fs            1.5.0    2020-07-31 [2] CRAN (R 3.6.3)
 generics      0.1.0    2020-10-31 [2] CRAN (R 3.6.3)
 ggplot2     * 3.3.3    2020-12-30 [2] CRAN (R 3.6.3)
 ggridges      0.5.3    2021-01-08 [2] CRAN (R 3.6.3)
 ggsci       * 2.9      2018-05-14 [2] CRAN (R 3.6.3)
 glue          1.4.2    2020-08-27 [2] CRAN (R 3.6.3)
 gtable        0.3.0    2019-03-25 [2] CRAN (R 3.6.3)
 haven         2.3.1    2020-06-01 [2] CRAN (R 3.6.3)
 here        * 1.0.1    2020-12-13 [2] CRAN (R 3.6.3)
 highr         0.8      2019-03-20 [2] CRAN (R 3.6.3)
 hms           1.0.0    2021-01-13 [2] CRAN (R 3.6.3)
 htmltools     0.5.1.1  2021-01-22 [2] CRAN (R 3.6.3)
 httr          1.4.2    2020-07-20 [2] CRAN (R 3.6.3)
 jquerylib     0.1.3    2020-12-17 [2] CRAN (R 3.6.3)
 jsonlite      1.7.2    2020-12-09 [2] CRAN (R 3.6.3)
 khroma      * 1.7.0    2021-09-02 [1] CRAN (R 3.6.3)
 knitr         1.31     2021-01-27 [2] CRAN (R 3.6.3)
 labeling      0.4.2    2020-10-20 [2] CRAN (R 3.6.3)
 lattice       0.20-41  2020-04-02 [2] CRAN (R 3.6.3)
 lifecycle     1.0.0    2021-02-15 [2] CRAN (R 3.6.3)
 lubridate     1.7.10   2021-02-26 [2] CRAN (R 3.6.3)
 magrittr      2.0.1    2020-11-17 [2] CRAN (R 3.6.3)
 memoise       2.0.0    2021-01-26 [2] CRAN (R 3.6.3)
 modelr        0.1.8    2020-05-19 [2] CRAN (R 3.6.3)
 munsell       0.5.0    2018-06-12 [2] CRAN (R 3.6.3)
 pillar        1.5.1    2021-03-05 [2] CRAN (R 3.6.3)
 pkgbuild      1.2.0    2020-12-15 [2] CRAN (R 3.6.3)
 pkgconfig     2.0.3    2019-09-22 [2] CRAN (R 3.6.3)
 pkgload       1.2.0    2021-02-23 [2] CRAN (R 3.6.3)
 plyr          1.8.6    2020-03-03 [2] CRAN (R 3.6.3)
 prettyunits   1.1.1    2020-01-24 [2] CRAN (R 3.6.3)
 pROC          1.17.0.1 2021-01-13 [2] CRAN (R 3.6.3)
 processx      3.4.5    2020-11-30 [2] CRAN (R 3.6.3)
 ps            1.6.0    2021-02-28 [2] CRAN (R 3.6.3)
 purrr       * 0.3.4    2020-04-17 [2] CRAN (R 3.6.3)
 R6            2.5.0    2020-10-28 [2] CRAN (R 3.6.3)
 Rcpp          1.0.6    2021-01-15 [2] CRAN (R 3.6.3)
 readr       * 1.4.0    2020-10-05 [2] CRAN (R 3.6.3)
 readxl        1.3.1    2019-03-13 [2] CRAN (R 3.6.3)
 remotes       2.2.0    2020-07-21 [2] CRAN (R 3.6.3)
 reprex        1.0.0    2021-01-27 [2] CRAN (R 3.6.3)
 reshape2    * 1.4.4    2020-04-09 [2] CRAN (R 3.6.3)
 rlang         0.4.10   2020-12-30 [2] CRAN (R 3.6.3)
 rmarkdown     2.7      2021-02-19 [2] CRAN (R 3.6.3)
 rprojroot     2.0.2    2020-11-15 [2] CRAN (R 3.6.3)
 rstudioapi    0.13     2020-11-12 [2] CRAN (R 3.6.3)
 rvest         1.0.0    2021-03-09 [2] CRAN (R 3.6.3)
 sass          0.3.1    2021-01-24 [2] CRAN (R 3.6.3)
 scales      * 1.1.1    2020-05-11 [2] CRAN (R 3.6.3)
 sessioninfo   1.1.1    2018-11-05 [2] CRAN (R 3.6.3)
 stringi       1.5.3    2020-09-09 [2] CRAN (R 3.6.3)
 stringr     * 1.4.0    2019-02-10 [2] CRAN (R 3.6.3)
 testthat      3.0.2    2021-02-14 [2] CRAN (R 3.6.3)
 tibble      * 3.1.0    2021-02-25 [2] CRAN (R 3.6.3)
 tidyr       * 1.1.3    2021-03-03 [2] CRAN (R 3.6.3)
 tidyselect    1.1.0    2020-05-11 [2] CRAN (R 3.6.3)
 tidyverse   * 1.3.0    2019-11-21 [2] CRAN (R 3.6.3)
 usethis       2.0.1    2021-02-10 [2] CRAN (R 3.6.3)
 utf8          1.2.1    2021-03-12 [2] CRAN (R 3.6.3)
 vctrs         0.3.6    2020-12-17 [2] CRAN (R 3.6.3)
 withr         2.4.1    2021-01-26 [2] CRAN (R 3.6.3)
 xfun          0.22     2021-03-11 [2] CRAN (R 3.6.3)
 xml2          1.3.2    2020-04-23 [2] CRAN (R 3.6.3)
 yaml          2.2.1    2020-02-01 [2] CRAN (R 3.6.3)
 yardstick   * 0.0.9    2021-11-22 [1] CRAN (R 3.6.3)

[1] /home/ad.abt.local/layc/R/x86_64-pc-linux-gnu-library/3.6
[2] /opt/R/3.6.3/lib64/R/library
LS0tCnRpdGxlOiAiUEZOQSAxIGNvbXBhcnRtZW50IFBsb3RzICh2OCkiCmF1dGhvcjogIldlaWhzdWVoIENoaXUsIENsYWlyZSBMYXksIFBhcmtlciBNYWxlayIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJUYnKWAiCmtuaXQ6IChmdW5jdGlvbihpbnB1dEZpbGUsIGVuY29kaW5nKSB7b3V0ZGlyID0gZmlsZS5wYXRoKGRpcm5hbWUoaW5wdXRGaWxlKSwgJ21hcmtkb3duJywgcGFzdGUwKGZvcm1hdChTeXMudGltZSgpLCAnJUYnKSkpOyBpZighZGlyLmV4aXN0cyhvdXRkaXIpKXtkaXIuY3JlYXRlKG91dGRpcil9OyBybWFya2Rvd246OnJlbmRlcihpbnB1dEZpbGUsIGVuY29kaW5nID0gZW5jb2RpbmcsIG91dHB1dF9mb3JtYXQgPSAnYWxsJywgb3V0cHV0X2RpciA9IG91dGRpcikgfSkKb3V0cHV0OgogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBkZl9wcmludDoga2FibGUKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDUKLS0tCgpgYGB7ciBzZXR1cH0KbGlicmFyeShjb2RhKQpsaWJyYXJ5KGJheWVzcGxvdCkgCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3NjaSkKbGlicmFyeShraHJvbWEpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHlhcmRzdGljaykKbGlicmFyeShoZXJlKQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGRwaSA9IDMwMCApCmBgYAoKU2V0IHVwIE1DU2ltIGZpbGUgCgpgYGB7ciBtY3NpbX0KIyB0aGlzIG1hcmtkb3duIGZpbGUgbXVzdCBiZSBzYXZlZCBpbiB0b3AgbGV2ZWwgZGlyZWN0b3J5IGZvciB0aGUgZm9sbG93aW5nIHRvIHdvcms7IHRoZSBtY3NpbSBjb2RlIGRlcGVuZHMgb24gZ2V0d2QgcmVzdWx0cy4KbWRpciA8LSAiTUNTaW0iCnNvdXJjZShoZXJlOjpoZXJlKG1kaXIsInNldHVwX01DU2ltLlIiKSkKIyBNYWtlIG1vZC5leGUgKHVzZWQgdG8gY3JlYXRlIG1jc2ltIGV4ZWN1dGFibGUgZnJvbSBtb2RlbCBmaWxlKQptYWtlbW9kKCkgCmBgYAoKIyMgU2V0IGZpbGVuYW1lcyBhbmQgbG9hZCBkYXRhCgoKYGBge3IgTUNNQyAgbW9kZWwgZmlsZSwgaW5jbHVkZT1GQUxTRX0Kc2V0LnNlZWQoMzE0MTU5KQpzYSA8LSAiQ2JnZC04MF8iICMgQUREIHNlbnNpdGl2aXR5IHRlc3QgdGFnIHRvIHBsb3QgZmlsZW5hbWVzOiBNX2xuX0NiZ2Rfc2MgdG8gYmUgY2VudGVyZWQgb24gbG4oMC44KSBpbnN0ZWFkIG9mIDAgKGRlY3JlYXNlZCBieSAyMCUpCgojIE1ha2UgbW9kZWwgZXhlY3V0YWJsZQptb2RlbF9maWxlPC0gIlBGQVNfMWNwdF92OC5wb3AuTUNNQy5tb2RlbC5SIgptYWtlbWNzaW0obW9kZWxfZmlsZSkKCmluX2ZpbGUgPC0gIlBGTkFfMWNwdF92OC5Qb3BNQ01DX01lYW5JbmRpdlRyYWluVGVzdC5pbi5SIiAKcGZhc19uYW1lIDwtIGdzdWIoIl8xY3B0X3Y4LlBvcE1DTUNfTWVhbkluZGl2VHJhaW5UZXN0LmluLlIiLCAiIiwgaW5fZmlsZSkKCnNhbXBzIDwtIGRhdGEuZnJhbWUoKQpjaGVja3MgPC0gZGF0YS5mcmFtZSgpCnNhbXBzLmxpc3QgPC0gbGlzdCgpCmZvciAoY2hhaW5udW0gaW4gMTo0KSB7CiAgb25lY2hhaW4gPC0gcmVhZC5kZWxpbShzdWIoIi5pbi5SIixwYXN0ZTAoY2hhaW5udW0sIi5vdXQiKSxpbl9maWxlKSkKICBzYW1wcy5saXN0W1tjaGFpbm51bV1dPC1tY21jKG9uZWNoYWluW2Zsb29yKG5yb3cob25lY2hhaW4pIC8gMik6bnJvdyhvbmVjaGFpbiksIC0xXSkKICBzYW1wcyA8LSByYmluZChzYW1wcyxzYW1wcy5saXN0W1tjaGFpbm51bV1dKQogIG9uZWNoZWNrIDwtIHJlYWQuZGVsaW0oc3ViKCIuaW4uUiIscGFzdGUwKGNoYWlubnVtLCIuY2hlY2sub3V0IiksaW5fZmlsZSkpCiAgb25lY2hlY2skQ2hhaW4gPC0gY2hhaW5udW0KICBjaGVja3MgPC0gcmJpbmQoY2hlY2tzLG9uZWNoZWNrKQp9CnNhbXBzLm1jbWNsaXN0IDwtIGFzLm1jbWMubGlzdChzYW1wcy5saXN0KQoKbG9hZCgiUEZOQV8xY3B0X3Y4X211bHRpY2hlY2suUmRhdGEiKQpgYGAKCiMjIFNldCB1cCBkYXRhc2V0CgpgYGB7ciBkYXRhc2V0LUxVVCwgY2FjaGUgPSBUUlVFfQppZF9sdXQgPC0gbXVsdGljaGVjayRkZl9jaGVjayAlPiUgc2VsZWN0KExldmVsKSAlPiUgdW5pcXVlICgpICAlPiUKICBtdXRhdGUoZGF0YXNldCA9IGMoIAogICAgcmVwKCJEZWNhdHVyIE0gVHJhaW4iLCA5KSwKICAgIHJlcCgiRGVjYXR1ciBGIFRyYWluIiwgOSksCiAgICByZXAoIkRlY2F0dXIgTSBUZXN0IiwgOSksCiAgICByZXAoIkRlY2F0dXIgRiBUZXN0IiwgMTApLAogICAgJ1BhdWxzYm9yby1UcmFpbicsJ0hvcnNoYW0tVHJhaW4nLAogICAgJ1dhcm1pbnN0ZXItVGVzdCcpLCAKICAgIFNleCA9IGMoIAogICAgcmVwKCJNIiwgOSksCiAgICByZXAoIkYiLCA5KSwKICAgIHJlcCgiTSIsIDkpLAogICAgcmVwKCJGIiwgMTApLAogICAgJ01peGVkJywgJ01peGVkJywgICdNaXhlZCcpLAogICAgQ2l0eSA9IGMoIAogICAgcmVwKCJEZWNhdHVyIiwgMTgpLAogICAgcmVwKCJEZWNhdHVyIiwgMTkpLAogICAgJ1BhdWxzYm9ybycsJ0hvcnNoYW0nLCdXYXJtaW5zdGVyJyksIAogICAgVHJhaW5fVGVzdCA9IGMoIAogICAgcmVwKCJUcmFpbiIsIDkpLAogICAgcmVwKCJUcmFpbiIsIDkpLAogICAgcmVwKCJUZXN0IiwgOSksCiAgICByZXAoIlRlc3QiLCAxMCksCiAgICAnVHJhaW4nLCAgJ1RyYWluJywgJ1Rlc3QnKSwKICAgIGRhdGF0eXBlID0gYygKICAgICAgcmVwKCJJbmRpdmlkdWFsIiw5KzkrOSsxMCksCiAgICAgIHJlcCgiU3VtbWFyeSIsMykpLAogICAgU2ltdWxhdGlvbiA9IHJvd19udW1iZXIoKSwKICAgIHZhcmlhYmxlID0gcGFzdGUwKGRhdGFzZXQsICIgIixTaW11bGF0aW9uKSkKCmlkX2x1dCRkYXRhc2V0IDwtIGZhY3RvcihpZF9sdXQkZGF0YXNldCxsZXZlbHM9CiAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIkRlY2F0dXIgTSBUcmFpbiIsIkRlY2F0dXIgRiBUcmFpbiIsIkFybnNiZXJnIE0gVHJhaW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBcm5zYmVyZyBGIFRyYWluIiwiRGVjYXR1ciBNIFRlc3QiLCJEZWNhdHVyIEYgVGVzdCIsIkFybnNiZXJnIE0gVGVzdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFybnNiZXJnIEYgVGVzdCIsIk1pbm5lc290YSBUcmFpbiIsIk1pbm5lc290YSBUZXN0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTHViZWNrLUJhcnRlbGwtVHJhaW4nLCAnTHViZWNrLUJhcnRlbGwtVGVzdCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0xpdHRsZSBIb2NraW5nLUJhcnRlbGwtVHJhaW4nLCAnTGl0dGxlIEhvY2tpbmctQmFydGVsbC1UZXN0JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTGl0dGxlIEhvY2tpbmctRW1tZXR0LVRlc3QnLCdQYXVsc2Jvcm8tVHJhaW4nLCdIb3JzaGFtLVRyYWluJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnV2FybWluc3Rlci1UZXN0JywnV2FycmluZ3Rvbi1UcmFpbicpKQppZF9sdXQkQ2l0eSA8LSBmYWN0b3IoaWRfbHV0JENpdHksbGV2ZWxzID0gCiAgICAgICAgICAgICAgICAgICAgICAgIGMoIkRlY2F0dXIiLCJBcm5zYmVyZyIsIk1pbm5lc290YSIsJ0x1YmVjay1CYXJ0ZWxsJywKICAgICAgICAgICAgICAgICAgICAgICAgICAnTGl0dGxlIEhvY2tpbmctQmFydGVsbCcsJ0xpdHRsZSBIb2NraW5nLUVtbWV0dCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgJ1BhdWxzYm9ybycsJ0hvcnNoYW0nLCdXYXJtaW5zdGVyJywnV2FycmluZ3RvbicpKQogCmluZGl2X2x1dCA8LSBpZF9sdXQgJT4lIAogIGZpbHRlcihDaXR5ICVpbiUgYygiRGVjYXR1ciIpKSAlPiUKICBtdXRhdGUoICBkYXRhc2V0ID0gYXMuZmFjdG9yKGRhdGFzZXQpKQoKbnYgPC0gZGF0YS5mcmFtZShkYXRhc2V0ID11bmlxdWUoaW5kaXZfbHV0JGRhdGFzZXQpLCAKICAgICAgICAgICB2YXJpYWJsZT0gcmVwKCJQb3AgR00iLCA0KSwKICAgICAgICAgICB0eXBlPSByZXAoIlBvcCBHTSIsIDQpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCmBgYAoKIyMgSW5kaXZpZHVhbCBwYXJhbWV0ZXJzCmBgYHtyIGluZGl2LXBhcm1zLCBjYWNoZSA9IFRSVUUsZmlnLmhlaWdodD0zLjUsZmlnLndpZHRoPTMuNSxkcGk9NjAwfQpzZXQuc2VlZCgzMTQxNTkpCgppbmRpdl9wYXJtcyA8LSBpbmRpdl9sdXQKbG5rcGFybW5hbWVzIDwtIHBhc3RlKCJsbl9rLiIsZ3N1YigiXyIsIi4iLGluZGl2X3Bhcm1zJExldmVsKSwiLiIsc2VwPSIiKQpsblZkcGFybW5hbWVzIDwtIHBhc3RlKCJsbl9WZC4iLGdzdWIoIl8iLCIuIixpbmRpdl9wYXJtcyRMZXZlbCksIi4iLHNlcD0iIikKCnBhcm1zYW1wIDwtIGFwcGx5KG11bHRpY2hlY2skcGFybXMuc2FtcCwyLHNhbXBsZSwxKQoKIyMgUmFuZG9tIHotc2NvcmUgZXN0aW1hdGUgb2YgZWFjaCBwYXJhbWV0ZXIKaW5kaXZfcGFybXMkbG5fay56LnNhbXAgPC0gcGFybXNhbXBbbG5rcGFybW5hbWVzXQppbmRpdl9wYXJtcyRsbl9WZC56LnNhbXAgPC0gcGFybXNhbXBbbG5WZHBhcm1uYW1lc10KCm5vcm1kIDwtIGRhdGEuZnJhbWUoeD1xbm9ybShwcG9pbnRzKDIwMCkpKQpub3JtZCR5IDwtIGRub3JtKG5vcm1kJHgpCgppcGxvdGs8LQogIGdncGxvdChzdWJzZXQoaW5kaXZfcGFybXMsVHJhaW5fVGVzdD09IlRyYWluIikpKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHg9bG5fay56LnNhbXAsYWZ0ZXJfc3RhdChkZW5zaXR5KSksYmlucz0xMCkrZmFjZXRfd3JhcCh+Q2l0eSxuY29sPTEpKwogICAgZ2VvbV9saW5lKGFlcyh4PXgseT15KSxkYXRhPW5vcm1kKSsKICAgIHhsYWIoIkluZGl2aWR1YWwgei1zY29yZXMgZm9yIGsiKSArIHRoZW1lX2J3KCkKCmlwbG90VmQ8LQogIGdncGxvdChzdWJzZXQoaW5kaXZfcGFybXMsVHJhaW5fVGVzdD09IlRyYWluIikpKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHg9bG5fVmQuei5zYW1wLGFmdGVyX3N0YXQoZGVuc2l0eSkpLGJpbnM9MTApK2ZhY2V0X3dyYXAofkNpdHksbmNvbD0xKSsKICAgIGdlb21fbGluZShhZXMoeD14LHk9eSksZGF0YT1ub3JtZCkrCiAgICB4bGFiKCJJbmRpdmlkdWFsIHotc2NvcmVzIGZvciBWZCIpICsgdGhlbWVfYncoKQoKcHJpbnQoaXBsb3RrKQpwcmludChpcGxvdFZkKQoKZ2dzYXZlKGZpbGUucGF0aCgib3V0cHV0LXBsb3RzIiwKICAgICAgICAgICAgIHBhc3RlMCggc2EsIkluZGl2X3pzY29yZXNfa19QRk5BLnBkZiIpKSxpcGxvdGssZHBpPTYwMCkKZ2dzYXZlKGZpbGUucGF0aCgib3V0cHV0LXBsb3RzIiwKICAgICAgICAgICAgIHBhc3RlMCggc2EsIkluZGl2X3pzY29yZXNfVmRfUEZOQS5wZGYiKSksaXBsb3RWZCxkcGk9NjAwKQpnZ3NhdmUoZmlsZS5wYXRoKCJvdXRwdXQtcGxvdHMiLAogICAgICAgICAgICAgcGFzdGUwKCBzYSwiSW5kaXZfenNjb3Jlc19rX1BGTkEucG5nIikpLGlwbG90ayxkcGk9NjAwKQpnZ3NhdmUoZmlsZS5wYXRoKCJvdXRwdXQtcGxvdHMiLAogICAgICAgICAgICAgcGFzdGUwKCBzYSwiSW5kaXZfenNjb3Jlc19WZF9QRk5BLnBuZyIpKSxpcGxvdFZkLGRwaT02MDApCmBgYAoKIyMgU2NhdHRlciBwbG90IG9mIHByZWRpY3Rpb25zIChtZWRpYW4gb2YgbXVsdGljaGVjayBzYW1wbGVzKSB2ZXJzdXMgZGF0YS4KClRoaXMgaXMgYSBGaWd1cmUgMiBwYW5lbC4gIE5lZWRlZCB0byB1c2UgInNjYWxlPTEuMSIgaW4gZ2dzYXZlIHRvIG1hdGNoIFBGT0EuCgpgYGB7ciBwcmVkaWN0aW9uLXZlcnN1cy1kYXRhICwgY2FjaGUgPSBUUlVFLGZpZy5oZWlnaHQ9My41LGZpZy53aWR0aD04LGRwaT02MDB9Cm5yb3cobXVsdGljaGVjayRkZl9jaGVjaykKbnJvdyhpZF9sdXQpCm11bHRpY2hlY2skZGZfY2hlY2sgJT4lIGxlZnRfam9pbihpZF9sdXQpICU+JSBucm93KCkKCm5hbWVzKG11bHRpY2hlY2skZGZfY2hlY2spCgptdWx0aWNoZWNrMiA8LSBtdWx0aWNoZWNrJGRmX2NoZWNrICU+JSBsZWZ0X2pvaW4oaWRfbHV0KSU+JSAKICBncm91cF9ieV9hdCAoIHZhcnMoLVByZWRpY3Rpb24pKSAlPiUgCiAgc3VtbWFyaXNlKFByZWRpY3Rpb24gPSBtZWRpYW4oUHJlZGljdGlvbikpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBncm91cF9ieShDaXR5KSAlPiUgCiAgbXV0YXRlKFRyYWluX1Rlc3QgPSBmYWN0b3IoVHJhaW5fVGVzdCwgbGV2ZWxzID0gYygiVHJhaW4iLCAiVGVzdCIpKSwKICAgICAgICAgYENpdHkgKGRhdGF0eXBlKWAgPSBmYWN0b3IgKHBhc3RlMCgiXG4iICwgQ2l0eSwgIlxuKCIsIGRhdGF0eXBlLCAiKVxuIikgKSwKICAgICAgICAgbGFiZWwgPSBjYXNlX3doZW4oVHJhaW5fVGVzdD09IlRyYWluIiB+ICJFOiBQRk5BIFRyYWluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhaW5fVGVzdD09IlRlc3QiICB+ICJGOiBQRk5BIFRlc3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIiIpKQogCgogI2RlZmluZSBjb2xvciBmb3IgdGVzdGluZyBib3hwbG90cwpicF9jb2xzIDwtIGMgKGFzLmNoYXJhY3RlciAoa2hyb21hOjpjb2xvdXIoIm11dGVkIikoOSkpICwgIiMxOTE5MTkiKSAgIApicF9jb2xzIDwtYnBfY29sc1tjKDEsIDcsIDk6OCldIyBwbG90X3NjaGVtZV9jb2xvdXJibGluZChicF9jb2xzKSAKCiMjIyBDcmVhdGUgYWVzdGhldGljcyBsb29rdXAKYWVzX2x1dCA8LSBtdWx0aWNoZWNrMiAlPiUgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShDaXR5LCBkYXRhdHlwZSwgIGBDaXR5IChkYXRhdHlwZSlgICkgJT4lIHN1bW1hcmlzZSAoKSAlPiUgdW5ncm91cCgpICU+JQogIG11dGF0ZSggY29scyA9IGJwX2NvbHMsIGNpdHlfZmlsbHMgPSAgIGJwX2NvbHMgLCAKICAgICAgICAgICMgZm9yIGluZGl2aWR1YWwgbGV2ZWwgb24gcG9pbnQgcGxvdCAobXVsdGljaGVjazIpLCBkYXJrZW4gb3V0bGluZXMgZm9yIHZpc2liaWxpdHksIHVzZSBzdGFuZGFyZCBjb2xvcnMgb3RoZXJ3aXNlCiAgICAgICAgIGNpdHlfb3V0bGluZXMgPSAgaWZfZWxzZShkYXRhdHlwZSA9PSAiSW5kaXZpZHVhbCIgICwgIGNvbG9yc3BhY2U6OmRhcmtlbihjaXR5X2ZpbGxzLCAwLjMpLCBjaXR5X2ZpbGxzKSAsICAKICAgICAgICAgc2hhcGVzID0gY2FzZV93aGVuKGRhdGF0eXBlID09ICJJbmRpdmlkdWFsIiAgJiBgQ2l0eWAgJWluJSBjKCdEZWNhdHVyJywgJ0FybnNiZXJnJywgJ01pbm5lc290YScpICAgfiAgMjMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhdHlwZSA9PSAiU3VtbWFyeSIgJmBDaXR5YCAlaW4lIGMoIkhvcnNoYW0iLCAiV2FybWluc3RlciIsICAiV2FycmluZ3RvbiIpIH4gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGF0eXBlID09ICJTdW1tYXJ5IiAmIGBDaXR5YCA9PSAiUGF1bHNib3JvIiB+IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gMTggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksIAogICAgICAgICBzaXplID0gaWZfZWxzZShkYXRhdHlwZSA9PSJJbmRpdmlkdWFsIiwgMS43NSwgMi41ICkgKSAgCgoKCnNvdXJjZSggcGFzdGUwKGdzdWIoYmFzZW5hbWUoaGVyZSgpKSwgJ3NoYXJlZF9mdW5jdGlvbnMnLCBoZXJlKCkpLCAnL3Bsb3Rfc2NhdHRlcl9tY2hlY2sucicpKQoKcDIgPC0gcGxvdF9zY2F0dGVyX21jaGVjayhkZnJhbWUgPSBtdWx0aWNoZWNrMiwgcGZhc19ub20gPSBwZmFzX25hbWUsIGFlc19sdXRfZm4gPSBhZXNfbHV0ICkKcHJpbnQocDIpIApnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIsIHBhc3RlMCggc2EsIm11bHRpY2hlY2twbG90XyIsIHBmYXNfbmFtZSwKICAgICAgICAgICAgICAgIi5wZGYiKSkscDIsZHBpPTYwMCwgc2NhbGU9MS4xKQpnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIsIHBhc3RlMCggc2EsIm11bHRpY2hlY2twbG90XyIsIHBmYXNfbmFtZSwKICAgICAgICAgICAgICAgIi5wbmciKSkscDIsZHBpPTYwMCwgc2NhbGU9MS4xKSAjIGRvZXNuJ3QgcHJvcGVybHkgaGFuZGxlICdcbicgdW5pY29kZSBmb3IgbGluZSBmZWVkLiBOb3Qgc3VyZSB3aHk7IHBvc3NpYmx5IGRldmljZSBvcGVucyBmcm9tIHdpbmRvd3Mgd29ya2luZyBlbnZpcm9ubWVudC4gCgoKbXVsdGljaGVjazIkUEZBUyA8LSAiUEZOQSIKbXVsdGlwbG90X3NjYXR0ZXJfZGF0IDwtIGxpc3QoYWVzX2x1dCA9IGFlc19sdXQsIG11bHRpY2hlY2syID0gbXVsdGljaGVjazIpICMgc2F2ZSBvdXQgZm9yIHVzZSBpbiBjb21tYmluZWQgcGxvdApzYXZlKG11bHRpcGxvdF9zY2F0dGVyX2RhdCwgZmlsZT0gInBmbmFfbXVsdGlwbG90X3NjYXR0ZXIuUmRhdGEiKQpgYGAKCiMjIFBhcnNlIG11bHRpY2hlY2sKCmBgYHtyIGRvLW11bHRpY2hlY2ssIGNhY2hlID0gVFJVRSwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9MTh9CgpkZl9jaGVjayA8LSBtdWx0aWNoZWNrJGRmX2NoZWNrCmRmX2NoZWNrIDwtIHN1YnNldChkZl9jaGVjayxEYXRhID4gMCkgCgpuMSA8LSBucm93KGRmX2NoZWNrKQppZF9jaGtzIDwtIGRmX2NoZWNrICU+JSBzZWxlY3QoTGV2ZWwpICU+JSB1bmlxdWUoKSAlPiUgYmluZF9jb2xzKGlkX2x1dCkgICU+JQogIG11dGF0ZShkYXRhc2V0ID0gYXMuZmFjdG9yKGRhdGFzZXQpLCBTZXggPSBhcy5mYWN0b3IoU2V4KSwgQ2l0eSA9IGFzLmZhY3RvcihDaXR5KSwgCiAgICAgICAgIFRyYWluX1Rlc3QgPSBhcy5mYWN0b3IoVHJhaW5fVGVzdCkpCgpkZl9jaGVjayA8LSBkZl9jaGVjayAlPiUgbGVmdF9qb2luKGlkX2Noa3MsIGJ5ID0gIlNpbXVsYXRpb24iKSU+JQogIG11dGF0ZShEYXRhc2V0ID0gcGFzdGUoYXMuY2hhcmFjdGVyKGRhdGFzZXQpLCBTaW11bGF0aW9uKSwKICAgICAgICAgU2V4ID0gb3JkZXJlZChTZXgsIGxldmVscyA9IGMoIk0iLCAiRiIsICJNaXhlZCIpLCAKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJNYWxlIiwgIkZlbWFsZSIsICJNaXhlZCAoYWxsIHNleGVzKSIpKSkKbjIgPC0gbnJvdyhkZl9jaGVjaykKaWYobjEgIT0gbjIpcHJpbnQoImR1cGxpY2F0ZXMgY3JlYXRlZCBpbiBpZC1sdXQgam9pbiIpCmBgYAoKCmBgYHtyIGRvLW11bHRpY2hlY2stMiwgY2FjaGUgPSBUUlVFLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0xOH0KZGZfY2hlY2skVGltZS5kZXNjIDwtIGFzLmNoYXJhY3RlcihwYXN0ZTAoIlQ9IixkZl9jaGVjayRUaW1lKSkKZGZfY2hlY2skVGltZS5kZXNjW2RmX2NoZWNrJFRpbWUuZGVzYyA9PSAiVD0xZS0wNiJdIDwtICJTdGVhZHlTdGF0ZSIKZGZfY2hlY2skRGF0YXNldC5UaW1lIDwtIGludGVyYWN0aW9uKGRmX2NoZWNrJERhdGFzZXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9jaGVjayRUaW1lLmRlc2MsbGV4Lm9yZGVyPVRSVUUpCmRmX2NoZWNrJERhdGFzZXQuVGltZSA8LSBmYWN0b3IoZGZfY2hlY2skRGF0YXNldC5UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscz1sZXZlbHMoZGZfY2hlY2skRGF0YXNldC5UaW1lKSkKY2FsaWJkYXRhIDwtIGRmX2NoZWNrWyxuYW1lcyhkZl9jaGVjaykgIT0gIlByZWRpY3Rpb24iXQpjYWxpYmRhdGEgPC0gY2FsaWJkYXRhWyFkdXBsaWNhdGVkKGNhbGliZGF0YSksXQpwcmludChjYWxpYmRhdGEpCiAKI011bHRpY2hlY2sgcGxvdAoKIyBTcGxpdCBTdGVhZHkgU3RhdGUgR3JvdXAgaW50byBkaWZmZXJlbnQgcG9wdWxhdGlvbnMgZm9yIGJveHBsb3QgZ3JvdXBpbmcKI2RmX2NoZWNrW2RmX2NoZWNrJFRpbWUuZGVzYyA9PSAiU3RlYWR5U3RhdGUiICYgZ3JlcGwoIkx1YmVjayIsZGZfY2hlY2skRGF0YXNldCksXSRUaW1lLmRlc2MgPC0gIkx1YmVjayIKI2RmX2NoZWNrW2RmX2NoZWNrJFRpbWUuZGVzYyA9PSAiU3RlYWR5U3RhdGUiICYgZ3JlcGwoIkxpdHRsZSBIb2NraW5nIixkZl9jaGVjayREYXRhc2V0KSxdJFRpbWUuZGVzYyA8LSAiTGl0dGxlIEhvY2tpbmciCmBgYAoKTW9kaWZ5IGFlc3RoZXRpY3MgbG9va3VwIHRhYmxlIGZvciBib3hwbG90cyAKYGBge3IgbW9kLWFlcy1sdXR9CiMjICBhZGRpdGlvbmFsIHNvdXJjZSBhZXN0aGV0aWMgbG9va3VwIHRhYmxlIGZvciBncmV5LXNjYWxlIHRpbWUgKHllYXJzKTsgIG1lcmdlZCBsZWdlbmRzIHNhdmUgc3BhY2Ugb24gcGxvdHRpbmcgb3V0cHV0CnRpbWVzIDwtIGRmX2NoZWNrJT4lIHNlbGVjdChUaW1lLmRlc2MsIFRpbWUpICU+JSAgdW5pcXVlICgpICU+JSAKICBtdXRhdGUocmFuayA9IHJhbmsoVGltZSkgLCBncmV5ID0gZ3JleS5jb2xvcnMoc3RhcnQ9MSxlbmQ9MC40LCBuID0gbigpKSwKICAgICAgICAgYWxwaGEgPSAocmFuaykvOCkgJT4lIAogIHNlbGVjdCgtVGltZSkKIApkZl9jaGVjayA8LSBkZl9jaGVjayAlPiUgbXV0YXRlIChsZWdlbmRfbGFiZWwgPSAocGFzdGUwKENpdHksICJcbiIsIFRpbWUuZGVzYyApICkpICMgYWRkIGxlZ2VuZC1sYWJlbHMKYWVzX2x1dCA8LSBkZl9jaGVjayAlPiUgCiAgc2VsZWN0KENpdHksIFRyYWluX1Rlc3QsIGRhdGF0eXBlLFRpbWUsIFRpbWUuZGVzYywgbGVnZW5kX2xhYmVsKSAlPiUgdW5pcXVlICgpICU+JQogICBsZWZ0X2pvaW4oYWVzX2x1dFssIGMoIkNpdHkiLCAiY29scyIpXSwgYnkgPSAiQ2l0eSIpICU+JSB1bmdyb3VwICgpICU+JSB1bmlxdWUgKCklPiUKICAgbGVmdF9qb2luICh0aW1lcywgYnkgPSAiVGltZS5kZXNjIikgJT4lIAogICBhcnJhbmdlKGRhdGF0eXBlLCBDaXR5LCBUcmFpbl9UZXN0LCBUaW1lKSAgICAlPiUgCiAgIG11dGF0ZShhbHBoYSA9IGlmX2Vsc2UoQ2l0eSA9PSAiSG9yc2hhbSIsIGFscGhhLzIsIGFscGhhKSkgJT4lICMgb3RoZXJ3aXNlIHRvbyBkYXJrIHdpdGggdGhpcyBjb2xvcgogIG11dGF0ZV9pZihpcy5mYWN0b3IsIGFzLmNoYXJhY3RlcikgCgpgYGAKCgojIyBEZWNhdHVyIGJveHBsb3RzCgpDaGFuZ2VkIGdyZXkgc3RhcnQgdG8gMSBpbnN0ZWFkIG9mIDAuOCwgZW5kIGF0IDAuNiBpbnN0ZWFkIG9mIDAuNC4KQ2hhbmdlZCBzaGFwZSBvZiBzeW1ib2xzIHNvIHRoZXkgYXJlIGZpbGxlZC4KCmBgYHtyIGRvLW11bHRpY2hlY2stZGVjYXR1ciwgY2FjaGUgPSBUUlVFLCBmaWcud2lkdGg9Ni41LCBmaWcuaGVpZ2h0PTMuNSxkcGk9NjAwfQojI0VGCgpkZl9kZWNhdCAgPC0gZGZfY2hlY2sgJT4lICAgCiAgZmlsdGVyKENpdHkgPT0gIkRlY2F0dXIiICYgVHJhaW5fVGVzdCAlaW4lIGMgKCJUcmFpbiIsICJUZXN0IikpICU+JSAKICBtdXRhdGUocGFuZWwgPSBvcmRlcmVkIChUcmFpbl9UZXN0LCBsZXZlbHMgPSBjICgiVHJhaW4iLCAiVGVzdCIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJFOiBQRk5BIERlY2F0dXIgVHJhaW4iLCAiRjogUEZOQSBEZWNhdHVyIFRlc3QiKSApKQoKYWVzX2x1dF9kZl9kZl9kZWNhdCA8LSBhZXNfbHV0ICU+JSAKICBmaWx0ZXIoQ2l0eSA9PSAiRGVjYXR1ciIgJiBUcmFpbl9UZXN0ICVpbiUgYyAoIlRyYWluIiwgIlRlc3QiKSkgJT4lIAogIG11dGF0ZV9pZihpcy5mYWN0b3IsIGFzLmNoYXJhY3RlcikgCgpzb3VyY2UoIHBhc3RlMChnc3ViKGJhc2VuYW1lKGhlcmUoKSksICdzaGFyZWRfZnVuY3Rpb25zJywgaGVyZSgpKSwgJy9wbG90X3N1bV9ib3hwbG90LnInKSkKCgpwbHRfdHJhaW4gPC0gcGxvdF9zdW1fYm94cGxvdCAgIChkZnJhbWUgPSBkZl9kZWNhdCwgYWVzX2x1dD0gYWVzX2x1dF9kZl9kZl9kZWNhdCwgZmFjZXRzID0gVFJVRSAsIHBmYXNfbm9tID0gcGZhc19uYW1lICAgICApIApwcmludChwbHRfdHJhaW4pCmdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIixwYXN0ZTAoIHNhLCJEZWNhdHVyVHJhaW5UZXN0Ym94cGxvdCIscGZhc19uYW1lLCIucGRmIikpLHBsdF90cmFpbixkcGk9NjAwKQpnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIscGFzdGUwKCBzYSwiRGVjYXR1clRyYWluVGVzdGJveHBsb3QiLHBmYXNfbmFtZSwiLnBuZyIpKSxwbHRfdHJhaW4sZHBpPTYwMCkKCgpgYGAKCiMjIEFsbCBib3hwbG90cwoKQ2hhbmdlZCBncmV5IHN0YXJ0IHRvIDEgaW5zdGVhZCBvZiAwLjgsIGVuZCBhdCAwLjYgaW5zdGVhZCBvZiAwLjQuCkFkZGVkIHNoYXBlcyBhbmQgZmlsbHMgdG8gZGF0YSBwb2ludHMuCgpgYGB7ciBkby1tdWx0aWNoZWNrLWFsbCwgY2FjaGUgPSBUUlVFLCBmaWcud2lkdGg9Ni41LCBmaWcuaGVpZ2h0PTMuNSxkcGk9NjAwfQoKbGV0cyA8LSBMRVRURVJTOwpuYW1lcyhsZXRzKVsxOihsZW5ndGgodW5pcXVlKGRmX2NoZWNrJGRhdGFzZXQpKS00KV08LWFzLmNoYXJhY3Rlcih1bmlxdWUoZGZfY2hlY2skZGF0YXNldCkpWzU6bGVuZ3RoKHVuaXF1ZShkZl9jaGVjayRkYXRhc2V0KSldCgpmb3IgKGQgaW4gdW5pcXVlKGRmX2NoZWNrJGRhdGFzZXQpKSB7ICMgZCA9IHVuaXF1ZShkZl9jaGVjayRkYXRhc2V0KVsxMV0KICAgIGRkc2V0IDwtIGRmX2NoZWNrICU+JSAgICAKICAgIGZpbHRlcihkYXRhc2V0ID09IGQpIAogICAgCiAgICBhZXNfbHV0X2Rkc2V0IDwtIGRkc2V0ICU+JSBzZWxlY3QobGVnZW5kX2xhYmVsLCAgQ2l0eSxUcmFpbl9UZXN0LGRhdGF0eXBlLCBUaW1lLmRlc2MgICkgJT4lIHVuaXF1ZSAoKSAlPiUgaW5uZXJfam9pbihhZXNfbHV0KQogICAgICAKICAgIGd0IDwtIGlmZWxzZShpcy5uYShsZXRzW2RdKSxkLHBhc3RlMChsZXRzW2RdLCI6ICIsIGQpKQogICAgcGx0IDwtIHBsb3Rfc3VtX2JveHBsb3QoZGZyYW1lID0gZGRzZXQsIGFlc19sdXQ9IGFlc19sdXRfZGRzZXQsIGd0aXRsZT0gZ3QsIGZhY2V0cyA9IEZBTFNFLCBwZmFzX25vbSA9IHBmYXNfbmFtZSkKICAgICAKICBwcmludChwbHQpCiAgZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLAogICAgICAgICAgICAgICAgcGFzdGUwKCBzYSwgZCwiLWJveHBsb3QtIiwgCiAgICAgICAgICAgICAgICBwZmFzX25hbWUsIi5wZGYiKSkgLAogICAgICAgICBwbHQsZHBpPTYwMCkKICAgIGdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIiwKICAgICAgICAgICAgICAgIHBhc3RlMCggc2EsIGQsIi1ib3hwbG90LSIsIAogICAgICAgICAgICAgICAgcGZhc19uYW1lLCIucG5nIikpICwKICAgICAgICAgcGx0LGRwaT02MDApCgoKfQoKIyMjIG1ha2UgVHJhaW5pbmcgcGxvdCAgCgpkZl9kX3RydCA8LSBkZl9jaGVjayAlPiUgICAKICAgICBmaWx0ZXIoIChUcmFpbl9UZXN0ID09ICJUcmFpbiIpICYgKChPdXRwdXRfVmFyID09ICJNX0NiZ2RfQ3NzIikgfCAoT3V0cHV0X1ZhciA9PSAiTV9Dc2VydW0iKSkpICU+JQogICAgIG11dGF0ZV9pZihpcy5mYWN0b3IsIGFzLmNoYXJhY3RlcikgJT4lICAjIGRyb3AgZmFjdG9yIGxldmVscyB1bnVzZWQKICAgICBtdXRhdGUoRGF0YXNldC5UaW1lID0gZmFjdG9yKERhdGFzZXQuVGltZSkpIAogCgogYWVzX2x1dF9kZl9kX3RydCA8LSAgZGZfZF90cnQgJT4lIHNlbGVjdChDaXR5LCBkYXRhdHlwZSxUaW1lLCBUaW1lLmRlc2MsIGxlZ2VuZF9sYWJlbCkgJT4lIAogICBpbm5lcl9qb2luKGFlc19sdXQgICkgJT4lIAogICBzZWxlY3QoLVRyYWluX1Rlc3QpICU+JSB1bmdyb3VwICgpICU+JSB1bmlxdWUgKCkgIAoKcGx0X3RyYWluIDwtICAgIHBsb3Rfc3VtX2JveHBsb3QoZGZyYW1lID0gZGZfZF90cnQsIGFlc19sdXQ9IGFlc19sdXRfZGZfZF90cnQsICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd0aXRsZT0iQTogU3VtbWFyeSBEYXRhIC0gVHJhaW4iICwgZmFjZXRzID0gRkFMU0UsIHBmYXNfbm9tID0gcGZhc19uYW1lICkKICBwcmludChwbHRfdHJhaW4pCiAgZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLCBwYXN0ZTAoIHNhLCAiU3VtbWFyeVRyYWluRGF0YWJveHBsb3QiLHBmYXNfbmFtZSwiLnBkZiIpKSwgcGx0X3RyYWluLGRwaT02MDApCiAgZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLCBwYXN0ZTAoIHNhLCAiU3VtbWFyeVRyYWluRGF0YWJveHBsb3QiLHBmYXNfbmFtZSwiLnBuZyIpKSwgcGx0X3RyYWluLGRwaT02MDApCgojIyMgIG1ha2UgVGVzdCBwbG90CmRmX2RfdGVzdCA8LSBkZl9jaGVjayAlPiUgICAKICAgIGZpbHRlcigoVHJhaW5fVGVzdCA9PSAiVGVzdCIpICYgCiAgICAgICAgICAgICAoKE91dHB1dF9WYXIgPT0gIk1fQ2JnZF9Dc3MiKSB8IChPdXRwdXRfVmFyID09ICJNX0NzZXJ1bSIpKSkgICU+JQogICAgIG11dGF0ZV9pZihpcy5mYWN0b3IsIGFzLmNoYXJhY3RlcikgJT4lICAjIGRyb3AgZmFjdG9yIGxldmVscyB1bnVzZWQKICAgICBtdXRhdGUoRGF0YXNldC5UaW1lID0gZmFjdG9yKERhdGFzZXQuVGltZSkpIAoKYWVzX2x1dF9kZl9kX3Rlc3QgPC0gIGRmX2RfdGVzdCAlPiUgc2VsZWN0KENpdHksIGRhdGF0eXBlLFRpbWUsIFRpbWUuZGVzYywgbGVnZW5kX2xhYmVsKSAlPiUgCiAgIGlubmVyX2pvaW4oYWVzX2x1dCAgKSAlPiUgCiAgIHNlbGVjdCgtVHJhaW5fVGVzdCkgJT4lIHVuZ3JvdXAgKCkgJT4lIHVuaXF1ZSAoKSAgCgpwbHRfdGVzdCA8LSBwbG90X3N1bV9ib3hwbG90KGRmcmFtZSA9IGRmX2RfdGVzdCwgYWVzX2x1dD0gYWVzX2x1dF9kZl9kX3Rlc3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd0aXRsZT0iQjogU3VtbWFyeSBEYXRhIC0gVGVzdCIsIGZhY2V0cyA9IEZBTFNFLCBwZmFzX25vbSA9IHBmYXNfbmFtZSkKICBwcmludChwbHRfdGVzdCkKICBnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIscGFzdGUwKCBzYSwgIlN1bW1hcnlUZXN0RGF0YWJveHBsb3QiLHBmYXNfbmFtZSwiLnBkZiIpKSwgcGx0X3Rlc3QsZHBpPTYwMCkgIAogICAgZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLHBhc3RlMCggc2EsICJTdW1tYXJ5VGVzdERhdGFib3hwbG90IixwZmFzX25hbWUsIi5wbmciKSksIHBsdF90ZXN0LGRwaT02MDApICAKYGBgCgojIyBQRk5BCiMjIyBCYWNrZ3JvdW5kIHBvc3RlcmlvcnMKClNob3dzIHNoaWZ0IGluIGJhY2tncm91bmQgZXN0aW1hdGUuCgpgYGB7ciBnZXQgYmFja2dyb3VuZCwgY2FjaGUgPSBUUlVFLGZpZy5oZWlnaHQ9NixmaWcud2lkdGg9NSxkcGk9NjAwfQoKZ21zY2FsZTwtMC44CgpkYXQgPC0gbXVsdGljaGVjayRwYXJtcy5zYW1wWyxncmVwKCJNX2xuX0NiZ2QiLG5hbWVzKG11bHRpY2hlY2skcGFybXMuc2FtcCkpXQpkYXRhc2V0bmFtZXMgPC0gYXMuY2hhcmFjdGVyKHVuaXF1ZShjYWxpYmRhdGEkZGF0YXNldCkpCmRhdGFzZXRuYW1lcyA8LSBnc3ViKCIgVHJhaW4iLCItVHJhaW4iLGRhdGFzZXRuYW1lcykKZGF0YXNldG5hbWVzIDwtIGdzdWIoIiBUZXN0IiwiLVRyYWluIixkYXRhc2V0bmFtZXMpCmRhdGFzZXRuYW1lcyA8LSBnc3ViKCIgTSIsIiIsZGF0YXNldG5hbWVzKQpkYXRhc2V0bmFtZXMgPC0gZ3N1YigiIEYiLCIiLGRhdGFzZXRuYW1lcykKZGF0YXNldG5hbWVzPC1kYXRhc2V0bmFtZXNbIWR1cGxpY2F0ZWQoZGF0YXNldG5hbWVzKV0KbmFtZXMoZGF0KSA8LSBkYXRhc2V0bmFtZXMKZGF0IDwtIGRhdFssZ3JlcCgiVHJhaW4iLG5hbWVzKGRhdCkpXQpkYXQuZGYgPC0gcGl2b3RfbG9uZ2VyKGRhdCwxOm5jb2woZGF0KSkKZGF0LmRmIDwtIHJiaW5kKGRhdC5kZiwKICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUobmFtZT0iUHJpb3IiLHZhbHVlPXJub3JtKDUwMDAsbT1sb2coZ21zY2FsZSksc2Q9MC40MDU1KSkpCmRhdC5kZiRuYW1lIDwtIGZhY3RvcihkYXQuZGYkbmFtZSxsZXZlbHM9cmV2KAogICAgICAgICAgICAgICAgICAgICAgICBjKCJQcmlvciIsZGF0YXNldG5hbWVzW2dyZXAoIlRyYWluIixkYXRhc2V0bmFtZXMpXSkpKQpkYXQuZGYkdmFsdWUgPC0gZXhwKGRhdC5kZiR2YWx1ZSkKCnA8LWdncGxvdChkYXQuZGYpKwogICNnZW9tX3Zpb2xpbihhZXMoeD1uYW1lLHk9dmFsdWUsZmlsbD1uYW1lPT0iUHJpb3IiKSkrCiAgZ2VvbV9ib3hwbG90KGFlcyh4PW5hbWUseT12YWx1ZSxmaWxsPW5hbWU9PSJQcmlvciIpLG91dGxpZXIuc2hhcGU9TkEpKwogIHNjYWxlX3lfbG9nMTAoKStjb29yZF9mbGlwKCkrCiAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9TlVMTCwgCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzPWMoIiMwMDk5ODgiLCAiI0VFNzczMyIgKSkrCiAgdGhlbWVfY2xhc3NpYygpICsgIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGdtc2NhbGUsY29sb3I9ImdyZXkiKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yPSJibGFjayIsc2l6ZT0xKSkrCiAgeWxhYigiUG9zdGVyaW9yIHNoaWZ0IGluIEJhY2tncm91bmQgQ29uY2VudHJhdGlvbiIpCgpwcmludChwKQpnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIscGFzdGUwKCBzYSwgIlBGTkFfR01fQ2JnZC5wZGYiKSkgLHAsZHBpPTYwMCkKZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLHBhc3RlMCggc2EsICJQRk5BX0dNX0NiZ2QucG5nIikpICxwLGRwaT02MDApCmBgYAoKCiMjIyBIYWxmLWxpZmUKCkZvciBQRk5BLCB0aGUgcG9wdWxhdGlvbiBHTSBvZiB0aGUgaGFsZi1saWZlIGhhcyBhIHBvc3RlcmlvciBkaXN0cmlidXRpb24gdGhhdCBpcyBuYXJyb3dlciB0aGFuIHRoZSBwcmlvciwgd2l0aCBhIHBvc3RlcmlvciBtZWRpYW4gKDk1JSBDSSkgZXN0aW1hdGUgb2YgMy4wNiAoMi4xNi00LjM3KSB5ZWFycy4gVGhlIHBvcHVsYXRpb24gR1NEIHBvc3RlcmlvciBpcyBsYXJnZXIgdGhhbiB0aGUgcHJpb3IgYXQgMS40NygxLjQ0LTEuNzUpLgoKYGBge3IgcG9zdGVyaW9yIGhpc3RvZ3JhbXMsIGNhY2hlID0gVFJVRX0KCmRhdCA8LSBtdWx0aWNoZWNrJHBhcm1zLnNhbXBbLGMoIk1fbG5fay4xLiIsIlZfbG5fay4xLiIsICJNX2xuX1ZkLjEuIiwgIlNEX2xuX1ZkLjEuIildCm5hbWVzKGRhdCkgPC0gYygiTV9sbl9rKDEpIiwiVl9sbl9rKDEpIiwgIk1fbG5fVmQoMSkiLCAiU0RfbG5fVmQoMSkiKQogIApzZXQuc2VlZCgzLjE0MTU5KQpkYXQkel9sbl9rIDwtIHJub3JtKG5yb3coZGF0KSkKZGF0JHpfbG5fVmQgPC0gcm5vcm0obnJvdyhkYXQpKQpkYXQgJT4lIHJlbmFtZV8oKQpkYXQkbG5fa19pIDwtIGRhdCRgTV9sbl9rKDEpYCArIHNxcnQoZGF0JGBWX2xuX2soMSlgKSpkYXQkel9sbl9rCmRhdCRsbl9WZF9pIDwtIGRhdCRgTV9sbl9WZCgxKWArIGRhdCRgU0RfbG5fVmQoMSlgKmRhdCR6X2xuX1ZkCmxpbm1vZCA8LSBsbShsbl9WZF9pIH4gbG5fa19pLGRhdGE9ZGF0KQpnZ3Bsb3QoZGF0KSArIGdlb21fcG9pbnQoYWVzKGxuX2tfaSxsbl9WZF9pKSkgKyAKICBsYWJzKHN1YnRpdGxlPXBhc3RlKCJBZGogUjIgPSIsc2lnbmlmKHN1bW1hcnkobGlubW9kKSRhZGouci5zcXVhcmVkLDIpKSkKYGBgCgoKIyMgQ2hlY2sgbm9ybWFsaXR5CgpgYGB7ciBub3JtYWxpdHksIGNhY2hlID0gVFJVRX0KCnFxbm9ybShkYXQkbG5fa19pLG1haW49ImxuIGsgUS1RIE5vcm1hbCIpCnFxbGluZShkYXQkbG5fa19pLGNvbD0icmVkIikKcGxvdChlY2RmKGRhdCRsbl9rX2kpKQp4IDwtIHNlcSgtMywxLDAuMDEpCm1fbG5fa19pIDwtICAgbWVhbihkYXQkbG5fa19pKQpzZF9sbl9rX2kgPC0gc2QoZGF0JGxuX2tfaSkKbGluZXMoeCxwbm9ybSh4LG1lYW49bV9sbl9rX2ksc2Q9c2RfbG5fa19pKSxjb2w9InJlZCIpCnRleHQobV9sbl9rX2ktMipzZF9sbl9rX2ksMC45LHBhc3RlKCJtID0iLHNpZ25pZihtX2xuX2tfaSw0KSwiXG5zZCA9IixzaWduaWYoc2RfbG5fa19pLDQpKSkKCnFxbm9ybShkYXQkbG5fVmRfaSxtYWluPSJsbiBWZCBRLVEgTm9ybWFsIikKcXFsaW5lKGRhdCRsbl9WZF9pLGNvbD0icmVkIikKcGxvdChlY2RmKGRhdCRsbl9WZF9pKSkKeCA8LSBzZXEoLTMsMSwwLjAxKQptX2xuX1ZkX2kgPC0gbWVhbihkYXQkbG5fVmRfaSkKc2RfbG5fVmRfaSA8LSBzZChkYXQkbG5fVmRfaSkKCmxpbmVzKHgscG5vcm0oeCxtZWFuPW1fbG5fVmRfaSxzZD1zZF9sbl9WZF9pKSxjb2w9InJlZCIpCnRleHQobV9sbl9WZF9pLTIqc2RfbG5fVmRfaSwwLjkscGFzdGUoIm0gPSIsc2lnbmlmKG1fbG5fVmRfaSw0KSwiXG5zZCA9IixzaWduaWYoc2RfbG5fVmRfaSw0KSkpCgpgYGAKCiMjIENhbGN1bGF0ZSB0YWJsZSB2YWx1ZXMgZm9yIGluZGl2aWR1YWwtbGV2ZWwKYGBge3IgbWFrZS1pbmRpdmlkdWFsLXBhcmFtLW91dCwgY2FjaGUgPSBUUlVFfQpobF9pIDwtIGxvZygyKS8gZXhwKGRhdCRsbl9rX2kpICMgaW5kaXZpZHVhbCBoYWxmLWxpZmUgCm1lZF9obF9pIDwtIHBhc3RlKHNpZ25pZiAobWVkaWFuIChobF9pKSwgMykpICMgbWVkaWFuIG9mIGluZGl2aWR1YWwgaGFsZi1saWZlCmNpX21lZF9obF9pIDwtICAgcGFzdGUoc2lnbmlmIChxdWFudGlsZShobF9pLCBwcm9iPWMoMC4wMjUsMC45NzUpKSwgMyksY29sbGFwc2U9Ii0iKSAjIDk1Y2kgbWVkIGluZGl2aWR1YWwgaGFsZmxpZmUKY2k5OF9tZWRfaGxfaSA8LSAgIHBhc3RlKHNpZ25pZiAocXVhbnRpbGUoaGxfaSwgcHJvYj1jKDAuMDEsMC45OSkpLCAzKSxjb2xsYXBzZT0iLSIpICMgOThjaSBtZWQgaW5kaXZpZHVhbCBoYWxmbGlmZQpnbV9obF9pIDwtIHBhc3RlKHNpZ25pZiAoZXhwKG1lYW4obG9nKGhsX2kpKSksIDMpKSAjIGdtICh3aGljaCBzaG91bGQgYmUgcmVhbGx5IGNsb3NlKQpnc2RfaGxfaSA8LSBwYXN0ZShzaWduaWYgKGV4cChzZChsb2coaGxfaSkpKSwgMykpICMgZ3NkIGluZGl2aWR1YWwKCm1lZF9WZF9pIDwtIHBhc3RlKHNpZ25pZiAobWVkaWFuKGV4cChkYXQkbG5fVmRfaSkpLCAzKSkgIyBtZWRpYW4gaW5kaXZpZHVhbCBWZApjaV9tZWRfVmRfaSA8LXBhc3RlKHNpZ25pZiAocXVhbnRpbGUoZXhwKGRhdCRsbl9WZF9pKSwgcHJvYj1jKDAuMDI1LDAuOTc1KSksIDMpLGNvbGxhcHNlPSItIikgIyA5NWNpIG1lZCBpbmRpdmlkdWFsIFZkCmNpOThfbWVkX1ZkX2kgPC1wYXN0ZShzaWduaWYgKHF1YW50aWxlKGV4cChkYXQkbG5fVmRfaSksIHByb2I9YygwLjAxLDAuOTkpKSwgMyksY29sbGFwc2U9Ii0iKSAjIDk4Y2kgbWVkIGluZGl2aWR1YWwgVmQKZ21fdmRfaSA8LSBwYXN0ZShzaWduaWYgKGV4cChtZWFuKGRhdCRsbl9WZF9pKSksIDMpKSAjIGdtICh3aGljaCBzaG91bGQgYmUgcmVhbGx5IGNsb3NlKQpnc2RfdmRfaTwtIHBhc3RlKHNpZ25pZiAoZXhwKHNkKGRhdCRsbl9WZF9pKSksIDMpKSAjIGdzZCBpbmRpdgoKbWVkX0NMX2kgPC0gcGFzdGUoc2lnbmlmIChtZWRpYW4oZXhwKGRhdCRsbl9WZF9pK2RhdCRsbl9rX2kpKSwgMykpICMgbWVkaWFuIGluZGl2aWR1YWwgQ0wKY2lfbWVkX0NMX2kgPC1wYXN0ZShzaWduaWYgKHF1YW50aWxlKGV4cChkYXQkbG5fVmRfaStkYXQkbG5fa19pKSwgcHJvYj1jKDAuMDI1LDAuOTc1KSksIDMpLGNvbGxhcHNlPSItIikgIyA5NWNpIG1lZCBpbmRpdmlkdWFsIENMCmNpOThfbWVkX0NMX2kgPC1wYXN0ZShzaWduaWYgKHF1YW50aWxlKGV4cChkYXQkbG5fVmRfaStkYXQkbG5fa19pKSwgcHJvYj1jKDAuMDEsMC45OSkpLCAzKSxjb2xsYXBzZT0iLSIpICMgOThjaSBtZWQgaW5kaXZpZHVhbCBDTApnbV9DTF9pIDwtIHBhc3RlKHNpZ25pZiAoZXhwKG1lYW4oZGF0JGxuX1ZkX2krZGF0JGxuX2tfaSkpLCAzKSkgIyBnbSAod2hpY2ggc2hvdWxkIGJlIHJlYWxseSBjbG9zZSkKZ3NkX0NMX2k8LSBwYXN0ZShzaWduaWYgKGV4cChzZChkYXQkbG5fVmRfaStkYXQkbG5fa19pKSksIDMpKSAjIGdzZCBpbmRpdgpgYGAKCgpgYGB7ciBoYWxmLWxpZmUsZmlnLmhlaWdodD0yLjUsZmlnLndpZHRoPTQsZHBpPTYwMH0KUEZOQV9wcmlvcnMgPC0gZGF0YS5mcmFtZSgKICBoYWxmbGlmZV9HTT0gbG9nKDIpL3Jsbm9ybSg1MDAwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFubG9nPS0xLjgwMTgxLHNkbG9nPTAuNDA1NSkpCk1fayA8LSBleHAoYXMubnVtZXJpYyhkYXQkYE1fbG5faygxKWApKQpQRk5BX2hhbGZsaWZlX0dNIDwtIGxvZygyKS9NX2sKClBGTkFfaGxnbV9wcl9tZWQgPC0gc2lnbmlmKG1lZGlhbihQRk5BX3ByaW9ycyRoYWxmbGlmZV9HTSwzKSkKUEZOQV9obGdtX3ByX21lZF85NWNpIDwtcGFzdGUoc2lnbmlmKHF1YW50aWxlKFBGTkFfcHJpb3JzJGhhbGZsaWZlX0dNLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2I9YygwLjAyNSwwLjk3NSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbGFwc2U9Ii0iKQoKUEZOQV9obF9tZWRpYW5fZ20gPC0gc2lnbmlmKG1lZGlhbihQRk5BX2hhbGZsaWZlX0dNKSwzKQpQRk5BX2hsX21lZGlhbl9nbV85NWNpIDwtIHBhc3RlKHNpZ25pZihxdWFudGlsZShQRk5BX2hhbGZsaWZlX0dNLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2I9YygwLjAyNSwwLjk3NSkpLDMpLGNvbGxhcHNlPSItIikKCnA8LWdncGxvdCgpKwogIHN0YXRfZGVuc2l0eShhZXMoaGFsZmxpZmVfR00sIGNvbG9yID0gIlByaW9yIiksZGF0YT1QRk5BX3ByaW9ycyxnZW9tPSJsaW5lIixzaXplPTIpKwogIHN0YXRfZGVuc2l0eShhZXMoUEZOQV9oYWxmbGlmZV9HTSxzdGF0KGRlbnNpdHkpLGNvbG9yPSJQb3N0ZXJpb3IiKSxnZW9tPSJsaW5lIixzaXplPTEuNSkrCiAgeGxpbSgwLDE1KSsKICBsYWJzKHRpdGxlID0gYnF1b3RlKCJFOiBQRk5BIn5UWzEvMl1+IlBvcHVsYXRpb24gR00iKSAgLAogICAgICAgc3VidGl0bGU9cGFzdGUoIlBvc3RlcmlvciBNZWRpYW4gKDk1JSBDSSk6ICIsCiAgICAgICAgICAgICAgICAgICAgICBQRk5BX2hsX21lZGlhbl9nbSwiICgiLAogICAgICAgICAgICAgICAgICAgICAgUEZOQV9obF9tZWRpYW5fZ21fOTVjaSwKICAgICAgICAgICAgICAgICAgICAgICIpIixzZXA9IiIpKSsKIHhsYWIoYnF1b3RlKCJQb3B1bGF0aW9uIEdNIn5UWzEvMl1+Iih5cnMpIikpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT1OVUxMLCAKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPWMoUHJpb3I9IiMwMDk5ODgiLCBQb3N0ZXJpb3I9IiNFRTc3MzMiICkpICsgCiAgdGhlbWVfY2xhc3NpYygpICsgIAogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSxsZWdlbmQucG9zaXRpb249YygwLjgsMC43KSwKICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj0iYmxhY2siLHNpemU9MSksCiAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9InRyYW5zcGFyZW50IiwgY29sb3I9TkEpKQpwcmludChwKQpnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIsIHBhc3RlMCggc2EsICJQRk5BX2hsX2dtLnBkZiIpKSAscCxkcGk9NjAwKQpnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIsIHBhc3RlMCggc2EsICJQRk5BX2hsX2dtLnBuZyIpKSAscCxkcGk9NjAwKQpgYGAKCgoKYGBge3IgUEZOQS1oYWxmLWxpZmUtZ3NkLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLGZpZy5oZWlnaHQ9Mi41LGZpZy53aWR0aD00LGRwaT02MDB9ClBGTkFfcHJpb3JzJGhhbGZsaWZlX0dTRCA9ICBleHAoc3FydChleHAocm5vcm0oNTAwMDAsbT1sb2coMC4yMDAwKSxzZD1sb2coMS4yNzUpKSkpKSAKUEZOQV9oYWxmbGlmZV9HU0QgPC0gZXhwKHNxcnQoZGF0JGBWX2xuX2soMSlgKSkKClBGTkFfaGxnc2RfcHJfbWVkIDwtIHNpZ25pZihtZWRpYW4oUEZOQV9wcmlvcnMkaGFsZmxpZmVfR1NELDMpKQpQRk5BX2hsZ3NkX3ByX21lZF85NWNpIDwtcGFzdGUoc2lnbmlmKHF1YW50aWxlKFBGTkFfcHJpb3JzJGhhbGZsaWZlX0dTRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iPWMoMC4wMjUsMC45NzUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxhcHNlPSItIikKUEZOQV9obF9nc2RfbWVkIDwtIHNpZ25pZihtZWRpYW4oUEZOQV9oYWxmbGlmZV9HU0QpLDMpClBGTkFfaGxfZ3NkX21lZF85NWNpIDwtIHBhc3RlKHNpZ25pZihxdWFudGlsZShQRk5BX2hhbGZsaWZlX0dTRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iPWMoMC4wMjUsMC45NzUpKSwzKSxjb2xsYXBzZT0iLSIpCnA8LWdncGxvdCgpKwogIHN0YXRfZGVuc2l0eShhZXMoaGFsZmxpZmVfR1NELCBjb2xvciA9ICJQcmlvciIpLGRhdGE9UEZOQV9wcmlvcnMsZ2VvbT0ibGluZSIsc2l6ZT0yKSsKICBzdGF0X2RlbnNpdHkoYWVzKFBGTkFfaGFsZmxpZmVfR1NELHN0YXQoZGVuc2l0eSksIGNvbG9yID0gIlBvc3RlcmlvciIpLGdlb209ImxpbmUiLHNpemU9MS41KSsKICB4bGltKDEsMykrCiAgbGFicyh0aXRsZSA9IGJxdW90ZSgiRjogUEZOQSJ+VFsxLzJdfiJQb3B1bGF0aW9uIEdTRCIpLCAKICAgICAgIHN1YnRpdGxlPXBhc3RlKCJQb3N0ZXJpb3IgTWVkaWFuICg5NSUgQ0kpOiAiLAogICAgICAgICAgICAgICAgICAgICAgUEZOQV9obF9nc2RfbWVkLCIgKCIsCiAgICAgICAgICAgICAgICAgICAgICBQRk5BX2hsX2dzZF9tZWRfOTVjaSwKICAgICAgICAgICAgICAgICAgICAgICIpIixzZXA9IiIpKSsKICB4bGFiKGJxdW90ZSgiUG9wdWxhdGlvbiBHU0QiflRbMS8yXSkpKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPU5VTEwsIAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9YyhQcmlvcj0iIzAwOTk4OCIsIFBvc3Rlcmlvcj0iI0VFNzczMyIgKSkgKyAKICAgdGhlbWVfY2xhc3NpYygpICsgIAogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSxsZWdlbmQucG9zaXRpb249YygwLjgsMC43KSwKICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj0iYmxhY2siLHNpemU9MSksCiAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9InRyYW5zcGFyZW50IiwgY29sb3I9TkEpKQpwcmludChwKQpnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIsIHBhc3RlMCggc2EsICJQRk5BX2hsX2dzZC5wZGYiKSksIHAsZHBpPTYwMCkKZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLCBwYXN0ZTAoIHNhLCAiUEZOQV9obF9nc2QucG5nIikpLCBwLGRwaT02MDApCmBgYAoKCiMjIyBEaXN0cmlidXRpb24gVm9sdW1lCkZvciBQRk5BLCB0aGUgZGF0YSB3ZXJlIG5vdCBwYXJ0aWN1bGFybHkgaW5mb3JtYXRpdmUsIGJ1dCBzbGlnaHRseSBpbmNyZWFzZWQgdGhlIGVzdGltYXRlIG9mIHRoZSBtZWRpYW4gdG8gMC4zMDgoMC4yMjMtMC41NDgpIHNsaWdodGx5LiBUaGV5IHdlcmUgbm90IGluZm9ybWF0aXZlIGFzIHRvIHRoZSBwb3B1bGF0aW9uIEdTRCwgd2l0aCB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbnMgZXNzZW50aWFsbHkgdW5jaGFuZ2VkIGZyb20gdGhlIHByaW9ycy4KYGBge3IgUEZOQS12ZC1nbSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSxmaWcuaGVpZ2h0PTIuNSxmaWcud2lkdGg9NCxkcGk9NjAwfQpQRk5BX3ByaW9ycyRWZF9HTSA8LSBybG5vcm0oNTAwMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbmxvZz0tMS43NzE5NiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZGxvZz0wLjI2MjQpClBGTkFfVmRfR00gPC0gZXhwKGRhdCRgTV9sbl9WZCgxKWApCgogCgpQRk5BX3ZkX2dtX3ByX21lZCA8LSBzaWduaWYobWVkaWFuKFBGTkFfcHJpb3JzJFZkX0dNLDMpKQpQRk5BX3ZkX2dtX3ByX21lZF85NWNpIDwtIHBhc3RlKHNpZ25pZihxdWFudGlsZShQRk5BX3ByaW9ycyRWZF9HTSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iPWMoMC4wMjUsMC45NzUpKSwgMyksIGNvbGxhcHNlPSItIikKUEZOQV92ZF9nbV9tZWQgPC0gc2lnbmlmKG1lZGlhbihQRk5BX1ZkX0dNKSwzKQpQRk5BX3ZkX2dtX21lZF85NWNpIDwtIHBhc3RlKHNpZ25pZihxdWFudGlsZShQRk5BX1ZkX0dNLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2I9YygwLjAyNSwwLjk3NSkpLDMpLGNvbGxhcHNlPSItIikKCnA8LWdncGxvdCgpKwogIHN0YXRfZGVuc2l0eShhZXMoVmRfR00sIGNvbG9yID0gIlByaW9yIiksZGF0YT1QRk5BX3ByaW9ycyxnZW9tPSJsaW5lIixzaXplPTIpKwogIHN0YXRfZGVuc2l0eShhZXMoUEZOQV9WZF9HTSxzdGF0KGRlbnNpdHkpLCBjb2xvciA9ICJQb3N0ZXJpb3IiKSxnZW9tPSJsaW5lIixzaXplPTEuNSkrCiAgeGxpbSgwLDEpK2xhYnModGl0bGUgPSBicXVvdGUoIkU6IFBGTkEiflZbZF1+IlBvcHVsYXRpb24gR00iKSwKICAgICAgICAgICAgICAgICBzdWJ0aXRsZT1wYXN0ZSgiUG9zdGVyaW9yIE1lZGlhbiAoOTUlIENJKTogIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQRk5BX3ZkX2dtX21lZCwiICgiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQRk5BX3ZkX2dtX21lZF85NWNpLCIpIixzZXA9IiIpKSsKICAgeGxhYihicXVvdGUoIlBvcHVsYXRpb24gR00iflZbZF1+IihsL2tnKSIpKSsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT1OVUxMLCAKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPWMoUHJpb3I9IiMwMDk5ODgiLCBQb3N0ZXJpb3I9IiNFRTc3MzMiICkpICAgKyAgCiAgdGhlbWVfY2xhc3NpYygpICsgIAogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSxsZWdlbmQucG9zaXRpb249YygwLjgsMC43KSwKICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj0iYmxhY2siLHNpemU9MSksCiAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9InRyYW5zcGFyZW50IiwgY29sb3I9TkEpKQpwcmludChwKQpnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIscGFzdGUwKCBzYSwgIlBGTkFfdmRfZ20ucGRmIikpLCBwLGRwaT02MDApCmdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIixwYXN0ZTAoIHNhLCAiUEZOQV92ZF9nbS5wbmciKSksIHAsZHBpPTYwMCkKCmBgYAoKCmBgYHtyIFBGTkEtdmQtc2QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsZmlnLmhlaWdodD0yLjUsZmlnLndpZHRoPTQsZHBpPTYwMH0KUEZOQV9wcmlvcnMkVmRfR1NEID0gZXhwKGFicyhybm9ybSg1MDAwMCxzZD0wLjE3KSkpClBGTkFfVmRfR1NEIDwtIGV4cChkYXQkYFNEX2xuX1ZkKDEpYCkKClBGTkFfdmRfZ3NkX3ByX21lZCA8LSBzaWduaWYobWVkaWFuKFBGTkFfcHJpb3JzJFZkX0dTRCwzKSkKUEZOQV92ZF9nc2RfcHJfbWVkXzk1Y2kgPC0gcGFzdGUoc2lnbmlmKHF1YW50aWxlKFBGTkFfcHJpb3JzJFZkX0dTRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iPWMoMC4wMjUsMC45NzUpKSwgMyksIGNvbGxhcHNlPSItIikKClBGTkFfdmRfZ3NkX21lZCA8LSBzaWduaWYobWVkaWFuKFBGTkFfVmRfR1NEKSwzKQpQRk5BX3ZkX2dzZF9tZWRfOTVjaSA8LSBwYXN0ZShzaWduaWYocXVhbnRpbGUoUEZOQV9WZF9HU0QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYj1jKDAuMDI1LDAuOTc1KSksMyksY29sbGFwc2U9Ii0iKQoKcDwtZ2dwbG90KCkrCiAgc3RhdF9kZW5zaXR5KGFlcyhWZF9HU0QsIGNvbG9yID0gIlByaW9yIiksZGF0YT1QRk5BX3ByaW9ycyxnZW9tPSJsaW5lIixzaXplPTIpKwogIHN0YXRfZGVuc2l0eShhZXMoUEZOQV9WZF9HU0Qsc3RhdChkZW5zaXR5KSwgY29sb3IgPSAiUG9zdGVyaW9yIiksZ2VvbT0ibGluZSIsc2l6ZT0xLjUpKwogIHhsaW0oMSwzKSsKICBsYWJzKHRpdGxlID0gYnF1b3RlKCJGOiBQRk5BIn5WW2RdfiJQb3B1bGF0aW9uIEdTRCAiKSwKICAgICAgIHN1YnRpdGxlPXBhc3RlKCJQb3N0ZXJpb3IgTWVkaWFuICg5NSUgQ0kpOiAiLAogICAgICAgICAgICAgICAgICAgICAgUEZOQV92ZF9nc2RfbWVkLCIgKCIsCiAgICAgICAgICAgICAgICAgICAgICBQRk5BX3ZkX2dzZF9tZWRfOTVjaSwKICAgICAgICAgICAgICAgICAgICAgICIpIixzZXA9IiIpKSsKICB4bGFiKGJxdW90ZSgiUG9wdWxhdGlvbiBHU0QiflZbZF0pKSsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT1OVUxMLCAKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPWMoUHJpb3I9IiMwMDk5ODgiLCBQb3N0ZXJpb3I9IiNFRTc3MzMiICkpICsgIAogIHRoZW1lX2NsYXNzaWMoKSArICAKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksbGVnZW5kLnBvc2l0aW9uPWMoMC44LDAuNyksCiAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9ImJsYWNrIixzaXplPTEpLAogICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJ0cmFuc3BhcmVudCIsIGNvbG9yPU5BKSkKcHJpbnQocCkKZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLHBhc3RlMCggc2EsICJQRk5BX3ZkX2dzZC5wZGYiKSksIHAsZHBpPTYwMCkKZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLHBhc3RlMCggc2EsICJQRk5BX3ZkX2dzZC5wbmciKSksIHAsZHBpPTYwMCkKYGBgCiMjIyBDbGVhcmFuY2UKCkNsIGlzIGsgKiBWZAoKYGBge3IgUEZOQS1jbC1nbSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSxmaWcuaGVpZ2h0PTIuNSxmaWcud2lkdGg9NCxkcGk9NjAwfQpQRk5BX3ByaW9ycyRDTF9HTSA8LSBQRk5BX3ByaW9ycyRWZF9HTSAqIChsb2coMikvUEZOQV9wcmlvcnMkaGFsZmxpZmVfR00pClBGTkFfQ0xfR00gPC0gZXhwKGRhdCRgTV9sbl9WZCgxKWAgKyBkYXQkYE1fbG5faygxKWApCgpQRk5BX2NsX2dtX3ByX21lZCA8LSBzaWduaWYobWVkaWFuKFBGTkFfcHJpb3JzJENMX0dNLDMpKQpQRk5BX2NsX2dtX3ByX21lZF85NWNpIDwtIHBhc3RlKHNpZ25pZihxdWFudGlsZShQRk5BX3ByaW9ycyRDTF9HTSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iPWMoMC4wMjUsMC45NzUpKSwgMyksIGNvbGxhcHNlPSItIikKUEZOQV9jbF9nbV9tZWQgPC0gc2lnbmlmKG1lZGlhbihQRk5BX0NMX0dNKSwzKQpQRk5BX2NsX2dtX21lZF85NWNpIDwtIHBhc3RlKHNpZ25pZihxdWFudGlsZShQRk5BX0NMX0dNLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2I9YygwLjAyNSwwLjk3NSkpLDMpLGNvbGxhcHNlPSItIikKCnA8LWdncGxvdCgpKwogIHN0YXRfZGVuc2l0eShhZXMoQ0xfR00sIGNvbG9yID0gIlByaW9yIiksZGF0YT1QRk5BX3ByaW9ycyxnZW9tPSJsaW5lIixzaXplPTIpKwogIHN0YXRfZGVuc2l0eShhZXMoUEZOQV9DTF9HTSxzdGF0KGRlbnNpdHkpLCBjb2xvciA9ICJQb3N0ZXJpb3IiKSxnZW9tPSJsaW5lIixzaXplPTEuNSkrCiAgeGxpbSgwLDAuMjUpK2xhYnModGl0bGUgPSAiQzogUEZOQSBDbGVhcmFuY2UgUG9wLiBHTSAiLHN1YnRpdGxlPXBhc3RlKCJQb3N0ZXJpb3IgTWVkaWFuICg5NSUgQ0kpOiAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBGTkFfY2xfZ21fbWVkLCIgKCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUEZOQV9jbF9nbV9tZWRfOTVjaSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiKSIsc2VwPSIiKSkrCiAgeGxhYigiUG9wLiBHTSBDTCAobC8oa2cteXIpKSIpKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPU5VTEwsIAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9YyhQcmlvcj0iIzAwOTk4OCIsIFBvc3Rlcmlvcj0iI0VFNzczMyIgKSkgKyAgCiAgdGhlbWVfY2xhc3NpYygpICsgIAogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSxsZWdlbmQucG9zaXRpb249YygwLjgsMC43KSwKICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj0iYmxhY2siLHNpemU9MSksCiAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9InRyYW5zcGFyZW50IiwgY29sb3I9TkEpKQpwcmludChwKQpnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIscGFzdGUwKCBzYSwgIlBGTkFfQ0xfZ20ucGRmIikpICxwLGRwaT02MDApCmdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIixwYXN0ZTAoIHNhLCAiUEZOQV9DTF9nbS5wbmciKSkgLHAsZHBpPTYwMCkKYGBgCgpgYGB7ciBQRk5BLUNMLXNkLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLGZpZy5oZWlnaHQ9Mi41LGZpZy53aWR0aD00LGRwaT02MDB9ClBGTkFfcHJpb3JzJENMX0dTRCA9IGV4cChzcXJ0KGxvZyhQRk5BX3ByaW9ycyRWZF9HU0QpXjIgKyAKICBsb2coUEZOQV9wcmlvcnMkaGFsZmxpZmVfR1NEKV4yKSkKUEZOQV9DTF9HU0QgPC0gZXhwKHNxcnQobG9nKFBGTkFfVmRfR1NEKV4yICsgCiAgbG9nKFBGTkFfaGFsZmxpZmVfR1NEKV4yKSkKClBGTkFfQ0xfZ3NkX3ByX21lZCA8LSBzaWduaWYobWVkaWFuKFBGTkFfcHJpb3JzJENMX0dTRCwzKSkKUEZOQV9DTF9nc2RfcHJfbWVkXzk1Y2kgPC0gcGFzdGUoc2lnbmlmKHF1YW50aWxlKFBGTkFfcHJpb3JzJENMX0dTRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iPWMoMC4wMjUsMC45NzUpKSwgMyksIGNvbGxhcHNlPSItIikKClBGTkFfQ0xfZ3NkX21lZCA8LSBzaWduaWYobWVkaWFuKFBGTkFfQ0xfR1NEKSwzKQpQRk5BX0NMX2dzZF9tZWRfOTVjaSA8LSBwYXN0ZShzaWduaWYocXVhbnRpbGUoUEZOQV9DTF9HU0QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYj1jKDAuMDI1LDAuOTc1KSksMyksY29sbGFwc2U9Ii0iKQoKcDwtZ2dwbG90KCkrCiAgc3RhdF9kZW5zaXR5KGFlcyhDTF9HU0QsIGNvbG9yID0gIlByaW9yIiksZGF0YT1QRk5BX3ByaW9ycyxnZW9tPSJsaW5lIixzaXplPTIpKwogIHN0YXRfZGVuc2l0eShhZXMoUEZOQV9DTF9HU0Qsc3RhdChkZW5zaXR5KSwgY29sb3IgPSAiUG9zdGVyaW9yIiksZ2VvbT0ibGluZSIsc2l6ZT0xLjUpKwogIHhsaW0oMSwzKSsKICBsYWJzKHRpdGxlID0gYnF1b3RlKCJIOiBQRk5BIn5DTH4iUG9wdWxhdGlvbiBHU0QgIiksCiAgICAgICBzdWJ0aXRsZT1wYXN0ZSgiUG9zdGVyaW9yIE1lZGlhbiAoOTUlIENJKTogIiwKICAgICAgICAgICAgICAgICAgICAgIFBGTkFfQ0xfZ3NkX21lZCwiICgiLAogICAgICAgICAgICAgICAgICAgICAgUEZOQV9DTF9nc2RfbWVkXzk1Y2ksCiAgICAgICAgICAgICAgICAgICAgICAiKSIsc2VwPSIiKSkrCiAgeGxhYihicXVvdGUoIlBvcHVsYXRpb24gR1NEIn5DTCkpKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPU5VTEwsIAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9YyhQcmlvcj0iIzAwOTk4OCIsIFBvc3Rlcmlvcj0iI0VFNzczMyIgKSkgKyAKICB0aGVtZV9jbGFzc2ljKCkgKyAgCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLGxlZ2VuZC5wb3NpdGlvbj1jKDAuOCwwLjcpLAogICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yPSJibGFjayIsc2l6ZT0xKSwKICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0idHJhbnNwYXJlbnQiLCBjb2xvcj1OQSkpCnByaW50KHApCmdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIixwYXN0ZTAoIHNhLCJQRk5BX0NMX2dzZC5wZGYiKSkgLHAsZHBpPTYwMCkKZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLHBhc3RlMCggc2EsIlBGTkFfQ0xfZ3NkLnBuZyIpKSAscCxkcGk9NjAwKQpgYGAKIyMgVGFibGUgc2lnbmlmaWNhbnQgZGlnaXQgdmFsdWVzCgpgYGB7ciB0YWJsZS12YXJzIH0KUEZOQV9obGdtX3ByX21lZCA8LSBwYXN0ZShzaWduaWYoUEZOQV9obGdtX3ByX21lZCwgMykpClBGTkFfaGxfbWVkaWFuX2dtPC0gcGFzdGUoc2lnbmlmKFBGTkFfaGxfbWVkaWFuX2dtLCAzKSkKUEZOQV9obGdzZF9wcl9tZWQ8LSBwYXN0ZShzaWduaWYoUEZOQV9obGdzZF9wcl9tZWQsIDMpKQpQRk5BX2hsX2dzZF9tZWQ8LSBwYXN0ZShzaWduaWYoUEZOQV9obF9nc2RfbWVkLCAzKSkKUEZOQV92ZF9nbV9wcl9tZWQ8LSBwYXN0ZShzaWduaWYoUEZOQV92ZF9nbV9wcl9tZWQsIDMpKQpQRk5BX3ZkX2dtX21lZDwtIHBhc3RlKHNpZ25pZihQRk5BX3ZkX2dtX21lZCwgMykpClBGTkFfdmRfZ3NkX3ByX21lZDwtIHBhc3RlKHNpZ25pZihQRk5BX3ZkX2dzZF9wcl9tZWQsIDMpKQpQRk5BX3ZkX2dzZF9tZWQ8LSBwYXN0ZShzaWduaWYoUEZOQV92ZF9nc2RfbWVkLCAzKSkKUEZOQV9jbF9nbV9wcl9tZWQ8LSBwYXN0ZShzaWduaWYoUEZOQV9jbF9nbV9wcl9tZWQsIDMpKQpQRk5BX2NsX2dtX21lZDwtIHBhc3RlKHNpZ25pZihQRk5BX2NsX2dtX21lZCwgMykpCmBgYAoKIyMjIFBvcHVsYXRpb24gbWVkaWFuIGVzdGltYXRlcyBbOTUlIENJXSAKCnwgUGFyYW1ldGVyICAgICAgICAgICAgICAgICAgICAgIHwgUHJpb3IgR00gICAgICB8IFBvc3RlcmlvciBHTSB8IFByaW9yICBHU0QgICAgfCBQb3N0ZXJpb3IgR1NEIHwgCnwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLTp8Oi0tLS0tLS0tLS0tLTp8Oi0tLS0tLS0tLS0tLS06fDotLS0tLS0tLS0tLS0tOnwgCnwgSGFsZi1saWZlICh5ZWFycykgIHwgYHIgcGFzdGUoUEZOQV9obGdtX3ByX21lZCkgYCB8ICAgYHIgcGFzdGUoUEZOQV9obF9tZWRpYW5fZ20pIGAgICAgfCBgciAgcGFzdGUoUEZOQV9obGdzZF9wcl9tZWQpIGAgICAgICAgICAgIHwgYHIgcGFzdGUoUEZOQV9obF9nc2RfbWVkKWAgIHwgCnwgSEwgIFs5NSUgQ0ldICB8YHIgcGFzdGUwKCJbIixQRk5BX2hsZ21fcHJfbWVkXzk1Y2ksIl0iKWAgfCBgciBwYXN0ZTAoICJbIixQRk5BX2hsX21lZGlhbl9nbV85NWNpLCJdIilgfCBgciBwYXN0ZTAoIlsiLFBGTkFfaGxnc2RfcHJfbWVkXzk1Y2ksIl0iKWB8IGByIHBhc3RlMCggIlsiLFBGTkFfaGxfZ3NkX21lZF85NWNpLCAiXSIpYHwKfCBWb2x1bWUgb2YgZGlzdHJpYnV0aW9uICAgIHwgYHIgcGFzdGUoUEZOQV92ZF9nbV9wcl9tZWQpIGAgfCAgICBgciBwYXN0ZSggIFBGTkFfdmRfZ21fbWVkKSBgfCAgIGByICBwYXN0ZShQRk5BX3ZkX2dzZF9wcl9tZWQpYCAgfGByICBwYXN0ZShQRk5BX3ZkX2dzZF9tZWQpYCB8ICAKfCAkVl9EJCBbOTUlIENJXSAgICB8YHIgcGFzdGUwKCAiWyIsUEZOQV92ZF9nbV9wcl9tZWRfOTVjaSwiXSIpYHwgYHIgcGFzdGUwKCAiWyIsUEZOQV92ZF9nbV9tZWRfOTVjaSwiXSIpYHwgYHIgcGFzdGUwKCJbIixQRk5BX3ZkX2dzZF9wcl9tZWRfOTVjaSwgIl0iKWB8IGByIHBhc3RlMCggICJbIixQRk5BX3ZkX2dzZF9tZWRfOTVjaSwgIl0iKWB8IAp8IENsZWFyYW5jZSAgICB8IGByIHBhc3RlKFBGTkFfY2xfZ21fcHJfbWVkKSBgIHwgICAgYHIgcGFzdGUoICBQRk5BX2NsX2dtX21lZCkgYHwgICBgciAgcGFzdGUoKWAgIHxgciAgcGFzdGUoKWAgfCAgCnwgJENMJCBbOTUlIENJXSAgICB8YHIgcGFzdGUwKCAiWyIsUEZOQV9jbF9nbV9wcl9tZWRfOTVjaSwiXSIpYHwgYHIgcGFzdGUwKCAiWyIsUEZOQV9jbF9nbV9tZWRfOTVjaSwiXSIpYHwgYHIgcGFzdGUwKCJbIiwgIl0iKWB8IGByIHBhc3RlMCggICJbIiwgIl0iKWB8IAogCgoKCiMjIyBJbmRpdmlkdWFsIFBvc3RlcmlvciBlc3RpbWF0ZXMgCgp8IFBhcmFtZXRlciAgICAgICAgICAgICAgICAgICAgICB8ICBtZWRpYW4gR00gIFs5NSUgQ0ldIFtbOTglIENJXV0gfCBHTSBjYWxjdWxhdG9yIGlucHV0ICB8ICBHU0QgaW5kaXZpZHVhbCB8CnwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS0tLS0tLS06fDotLS0tLS0tLS0tLS0tLS0tLS0tLTp8Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLTp8IAp8IEhhbGYtbGlmZSAoeWVhcnMpICAgICAgICAgICAgICB8IGByICBwYXN0ZShtZWRfaGxfaSwgIlsiLGNpX21lZF9obF9pLCJdIiwgIltbIixjaTk4X21lZF9obF9pLCJdXSIpIGAgfCBgciAgcGFzdGUoZ21faGxfaSkgYCB8IGByICBwYXN0ZShnc2RfaGxfaSkgYHwKfCBWb2x1bWUgb2YgZGlzdHJpYnV0aW9uICRWX0QkICAgfCBgciAgcGFzdGUobWVkX1ZkX2ksICJbIixjaV9tZWRfVmRfaSwiXSIsICJbWyIsY2k5OF9tZWRfVmRfaSwiXV0iKSBgIHwgYHIgIHBhc3RlKGdtX3ZkX2kpIGAgfCBgciAgcGFzdGUoZ3NkX3ZkX2kpIGB8IAp8IENsZWFyYW5jZSAoTC9rZy15cikgICB8IGByICBwYXN0ZShtZWRfQ0xfaSwgIlsiLGNpX21lZF9DTF9pLCJdIiwgIltbIixjaTk4X21lZF9DTF9pLCJdXSIpIGAgfCBgciAgcGFzdGUoZ21fQ0xfaSkgYCB8IGByICBwYXN0ZShnc2RfQ0xfaSkgYHwgCgpgYGB7ciBlY2hvPUZBTFNFfQpkZXZ0b29sczo6c2Vzc2lvbl9pbmZvKCkKYGBg